PageSourceSearch

https://connecteam.com/wp-content/themes/connecteam/inc/sections/s…/section-slidertabs.js?ver=06m79x

js connecteam.com collected 2026-09-24 08:59:46 UTC 13,732 bytes, 464 lines download raw bytes

1jQuery(document).ready(function ($) {
2  var TAB_ANIMATION_SPEED = 360
3  var SLIDE_AUTOPLAY_SPEED = 4000
4  var $modalSlider = null
5
6  $('.section-slidertabs').each(function () {
7    initSliderTabs($(this))
8  })
9
10  initSectionMediaHydration()
11  initSectionAutoplay()
12  initVideoModal()
13
14  function initSliderTabs ($section) {
15    var $tabs = $section.find('[data-slidertabs-tab]')
16    var $panels = $section.find('[data-slidertabs-panel]')
17    var $activeTitle = $section.find('[data-slidertabs-active-title]')
18
19    initPanelSlider($panels.filter('.active'))
20
21    $tabs.on('click', function () {
22      var $tab = $(this)
23      var tabIndex = $tab.data('slidertabs-tab')
24      var $panel = $panels.filter('[data-slidertabs-panel="' + tabIndex + '"]')
25
26      if ($tab.hasClass('active')) return
27
28      $tabs.removeClass('active').attr('aria-selected', 'false')
29      $tab.addClass('active').attr('aria-selected', 'true')
30
31      animateTabTitle($section, $activeTitle, tabIndex)
32      pausePanelSliders($panels)
33
34      $panels.removeClass('active').attr('hidden', true)
35      $panel.addClass('active').removeAttr('hidden')
36
37      initPanelSlider($panel)
38      $panel.find('[data-slidertabs-slider]').slick('setPosition')
39
40      if (isSectionAutoplayStarted($section)) {
41        playPanelSlider($panel)
42      }
43
44      if (typeof sendGAEvent === 'function') {
45        sendGAEvent('click_to_tab', {
46          title_text: $.trim($tab.text()),
47        })
48      }
49    })
50  }
51
52  function animateTabTitle ($section, $activeTitle, tabIndex) {
53    if (!$activeTitle.length) return
54
55    $activeTitle
56      .removeClass('is-entering')
57      .addClass('is-changing')
58
59    window.setTimeout(function () {
60      updateTabTitle($section, $activeTitle, tabIndex)
61
62      $activeTitle
63        .removeClass('is-changing')
64        .addClass('is-entering')
65
66      window.setTimeout(function () {
67        $activeTitle.removeClass('is-entering')
68      }, TAB_ANIMATION_SPEED)
69    }, TAB_ANIMATION_SPEED / 2)
70  }
71
72  function updateTabTitle ($section, $activeTitle, tabIndex) {
73    if (!$activeTitle.length) return
74
75    var $template = $section.find('[data-slidertabs-title-template="' + tabIndex + '"]')
76    if (!$template.length) return
77
78    $activeTitle.html($template.html())
79  }
80
81  function initPanelSlider ($panel) {
82    if (!$panel.length) return
83
84    var $slider = $panel.find('[data-slidertabs-slider]')
85    if (!$slider.length || $slider.hasClass('slick-initialized')) return
86
87    $panel.on('click', '.section-slidertabs__arrows .slick-arrow', function () {
88      $slider.data('slidertabs-arrow-change', true)
89    })
90
91    $slider.on('swipe', function () {
92      $slider.data('slidertabs-user-change', true)
93    })
94
95    $slider.on('init reInit afterChange', function (event, slick, currentSlide) {
96      updateProgress($panel, slick, currentSlide || 0)
97
98      if (event.type !== 'afterChange') return
99
100      var currentSlideElement = slick.$slides.eq(currentSlide)
101      var logoAlt = currentSlideElement.find('.section-slidertabs__logo').attr('alt') || ''
102
103      if ($slider.data('slidertabs-arrow-change')) {
104        if (typeof sendGAEvent === 'function') {
105          sendGAEvent('click_on_arrow', {
106            title_text: logoAlt,
107          })
108        }
109
110        $slider.removeData('slidertabs-arrow-change')
111        return
112      }
113
114      if ($slider.data('slidertabs-user-change')) {
115        if (typeof sendGAEvent === 'function') {
116          sendGAEvent('slider_swipe', {
117            title_text: logoAlt,
118          })
119        }
120
121        $slider.removeData('slidertabs-user-change')
122      }
123    })
124
125    $slider.slick({
126      infinite: true,
127      slidesToShow: 1,
128      slidesToScroll: 1,
129      dots: false,
130      arrows: true,
131      appendArrows: $panel.find('.section-slidertabs__arrows'),
132      prevArrow: "<button type='button' class='slick-prev' aria-label='Previous slide'><svg xmlns='http://www.w3.org/2000/svg' width='24' height='15' viewBox='0 0 24 15' fill='none' aria-hidden='true'><path d='M16.5 1L23 7.5M23 7.5L16.5 14M23 7.5H1' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg></button>",
133      nextArrow: "<button type='button' class='slick-next' aria-label='Next slide'><svg xmlns='http://www.w3.org/2000/svg' width='24' height='15' viewBox='0 0 24 15' fill='none' aria-hidden='true'><path d='M16.5 1L23 7.5M23 7.5L16.5 14M23 7.5H1' stroke='currentColor' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'/></svg></button>",
134      cssEase: 'ease',
135      autoplay: false,
136      autoplaySpeed: SLIDE_AUTOPLAY_SPEED,
137      pauseOnFocus: false,
138      pauseOnHover: false,
139      adaptiveHeight: false,
140      responsive: [
141        {
142          breakpoint: 991,
143          settings: {
144            arrows: true,
145            swipe: true,
146          },
147        },
148      ],
149    })
150  }
151
152  function initSectionAutoplay () {
153    var sections = document.querySelectorAll('.section-slidertabs')
154    if (!sections.length) return
155
156    if (!('IntersectionObserver' in window)) {
157      $('.section-slidertabs').each(function () {
158        startSectionAutoplay($(this))
159      })
160      return
161    }
162
163    var observer = new IntersectionObserver(function (entries) {
164      entries.forEach(function (entry) {
165        if (!entry.isIntersecting) return
166
167        startSectionAutoplay($(entry.target))
168        observer.unobserve(entry.target)
169      })
170    }, {
171      threshold: 0.2,
172    })
173
174    sections.forEach(function (section) {
175      observer.observe(section)
176    })
177  }
178
179  function startSectionAutoplay ($section) {
180    if (isSectionAutoplayStarted($section)) return
181
182    hydrateSectionMedia($section)
183    $section.data('slidertabs-autoplay-started', true)
184    playPanelSlider($section.find('[data-slidertabs-panel].active'))
185  }
186
187  function isSectionAutoplayStarted ($section) {
188    return $section.data('slidertabs-autoplay-started') === true
189  }
190
191  function playPanelSlider ($panel) {
192    $panel.find('[data-slidertabs-slider].slick-initialized').slick('slickPlay')
193  }
194
195  function pausePanelSliders ($panels) {
196    $panels.find('[data-slidertabs-slider].slick-initialized').each(function () {
197      $(this).slick('slickPause')
198    })
199  }
200
201  function updateProgress ($panel, slick, currentSlide) {
202    var slideCount = slick.slideCount || 1
203    var progress = ((currentSlide + 1) / slideCount) * 100
204
205    $panel.find('.section-slidertabs__progressBar').css('width', progress + '%')
206  }
207
208  function initSectionMediaHydration () {
209    var sections = document.querySelectorAll('.section-slidertabs')
210    if (!sections.length) return
211
212    if (!('IntersectionObserver' in window)) {
213      $('.section-slidertabs').each(function () {
214        hydrateSectionMedia($(this))
215      })
216      return
217    }
218
219    var observer = new IntersectionObserver(function (entries) {
220      entries.forEach(function (entry) {
221        if (!entry.isIntersecting) return
222
223        hydrateSectionMedia($(entry.target))
224        observer.unobserve(entry.target)
225      })
226    }, {
227      rootMargin: '0px',
228      threshold: 0,
229    })
230
231    sections.forEach(function (section) {
232      observer.observe(section)
233    })
234  }
235
236  function hydrateSectionMedia ($section) {
237    hydrateSectionImages($section)
238    hydrateSectionVideos($section)
239  }
240
241  function hydrateSectionImages ($section) {
242    if ($section.attr('data-images-eager-loaded') === 'true') return
243
244    $section.find('source[data-srcset]').each(function () {
245      var source = this
246
247      source.setAttribute('srcset', source.dataset.srcset)
248      source.removeAttribute('data-srcset')
249    })
250
251    $section.find('img[data-src]').each(function () {
252      var image = this
253      var src = image.dataset.src
254
255      if (!src) return
256
257      image.setAttribute('src', src)
258      image.removeAttribute('data-src')
259      image.loading = 'eager'
260      image.setAttribute('loading', 'eager')
261    })
262
263    $section.attr('data-images-eager-loaded', 'true')
264  }
265
266  function hydrateSectionVideos ($section) {
267    if ($section.attr('data-videos-hydrated') === 'true') return
268
269    $section.find('[data-slidertabs-video]').each(function () {
270      var $trigger = $(this)
271      var desktopUrl = $trigger.attr('data-video-desktop-src') || ''
272      var mobileUrl = $trigger.attr('data-video-mobile-src') || ''
273
274      if (desktopUrl) {
275        $trigger.attr('data-video-desktop', desktopUrl)
276      }
277
278      if (mobileUrl) {
279        $trigger.attr('data-video-mobile', mobileUrl)
280      }
281
282      preloadVideoSources($section, $trigger)
283    })
284
285    $section.attr('data-videos-hydrated', 'true')
286  }
287
288  function preloadVideoSources ($section, $trigger) {
289    var videoType = $trigger.data('video-type')
290    var urls = uniqueUrls([
291      $trigger.attr('data-video-desktop') || '',
292      $trigger.attr('data-video-mobile') || '',
293    ])
294
295    if (!urls.length) return
296
297    var $preloadContainer = getPreloadContainer($section)
298
299    urls.forEach(function (url) {
300      var preloadKey = encodeURIComponent(url)
301
302      if ($preloadContainer.find('[data-video-preload="' + preloadKey + '"]').length) return
303
304      if (videoType === 'mp4') {
305        $('<video />', {
306          'data-video-preload': preloadKey,
307          muted: true,
308          playsinline: true,
309          preload: 'metadata',
310          src: url,
311        }).appendTo($preloadContainer)
312      } else {
313        $('<iframe />', {
314          'data-video-preload': preloadKey,
315          loading: 'lazy',
316          src: removeAutoplayParam(url),
317          tabindex: '-1',
318          'aria-hidden': 'true',
319        }).appendTo($preloadContainer)
320      }
321    })
322  }
323
324  function getPreloadContainer ($section) {
325    var $preloadContainer = $section.find('.section-slidertabs__videoPreloads')
326
327    if (!$preloadContainer.length) {
328      $preloadContainer = $('<div class="section-slidertabs__videoPreloads" aria-hidden="true"></div>')
329      $section.append($preloadContainer)
330    }
331
332    return $preloadContainer
333  }
334
335  function uniqueUrls (urls) {
336    var seenUrls = {}
337
338    return urls.filter(function (url) {
339      if (!url || seenUrls[url]) return false
340
341      seenUrls[url] = true
342      return true
343    })
344  }
345
346  function initVideoModal () {
347    var $modal = $(
348      '<div class="section-slidertabs-modal" aria-hidden="true">' +
349        '<div class="section-slidertabs-modal__backdrop" data-slidertabs-close></div>' +
350        '<div class="section-slidertabs-modal__dialog" role="dialog" aria-modal="true" aria-label="Testimonial video">' +
351          '<button class="section-slidertabs-modal__close" type="button" aria-label="Close video" data-slidertabs-close></button>' +
352          '<div class="section-slidertabs-modal__content"></div>' +
353        '</div>' +
354      '</div>'
355    )
356
357    $('body').append($modal)
358
359    $(document).on('click', '[data-slidertabs-video]', function (event) {
360      event.preventDefault()
361      event.stopPropagation()
362
363      var $trigger = $(this)
364      hydrateSectionVideos($trigger.closest('.section-slidertabs'))
365
366      var videoUrl = getVideoUrl($trigger)
367      var videoType = $trigger.data('video-type')
368      var $slider = $trigger.closest('[data-slidertabs-slider]')
369
370      if (!videoUrl) return
371
372      if ($slider.hasClass('slick-initialized')) {
373        $modalSlider = $slider
374        $slider.slick('slickPause')
375      }
376
377      openVideoModal($modal, videoUrl, videoType)
378    })
379
380    $modal.on('click', '[data-slidertabs-close]', function () {
381      closeVideoModal($modal)
382    })
383
384    $(document).on('keyup', function (event) {
385      if (event.key === 'Escape' && $modal.hasClass('active')) {
386        closeVideoModal($modal)
387      }
388    })
389  }
390
391  function getVideoUrl ($trigger) {
392    var desktopUrl = $trigger.attr('data-video-desktop') || $trigger.attr('data-video-desktop-src') || ''
393    var mobileUrl = $trigger.attr('data-video-mobile') || $trigger.attr('data-video-mobile-src') || ''
394
395    if (window.matchMedia('(max-width: 767px)').matches && mobileUrl) {
396      return mobileUrl
397    }
398
399    return desktopUrl || mobileUrl
400  }
401
402  function openVideoModal ($modal, videoUrl, videoType) {
403    var $content = $modal.find('.section-slidertabs-modal__content')
404
405    if (videoType === 'mp4') {
406      $content.html(
407        '<video controls autoplay playsinline>' +
408          '<source src="' + escapeAttribute(videoUrl) + '" type="video/mp4">' +
409        '</video>'
410      )
411    } else {
412      $content.html(
413        '<iframe src="' + escapeAttribute(addAutoplayParams(videoUrl)) + '" frameborder="0" allow="autoplay; fullscreen; picture-in-picture" allowfullscreen></iframe>'
414      )
415    }
416
417    $('body').addClass('section-slidertabs-modal-open')
418    $modal.addClass('active').attr('aria-hidden', 'false')
419  }
420
421  function closeVideoModal ($modal) {
422    $modal.removeClass('active').attr('aria-hidden', 'true')
423    $modal.find('.section-slidertabs-modal__content').empty()
424    $('body').removeClass('section-slidertabs-modal-open')
425
426    if ($modalSlider && $modalSlider.hasClass('slick-initialized')) {
427      $modalSlider.slick('slickPlay')
428    }
429
430    $modalSlider = null
431  }
432
433  function addAutoplayParams (url) {
434    var separator = url.indexOf('?') === -1 ? '?' : '&'
435    var nextUrl = url
436
437    if (nextUrl.indexOf('autoplay=') === -1) {
438      nextUrl += separator + 'autoplay=1'
439      separator = '&'
440    }
441
442    if (nextUrl.indexOf('playsinline=') === -1) {
443      nextUrl += separator + 'playsinline=1'
444    }
445
446    return nextUrl
447  }
448
449  function removeAutoplayParam (url) {
450    return String(url)
451      .replace(/([?&])autoplay=1&?/g, '$1')
452      .replace(/[?&]$/, '')
453      .replace(/\?&/, '?')
454  }
455
456  function escapeAttribute (value) {
457    return String(value)
458      .replace(/&/g, '&amp;')
459      .replace(/"/g, '&quot;')
460      .replace(/'/g, '&#39;')
461      .replace(/</g, '&lt;')
462      .replace(/>/g, '&gt;')
463  }
464})

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.