PageSourceSearch

https://techchannel.com/wp-content/themes/tech-channel-theme/assets/js/main.js?ver=2024.02.23.1790909777

js techchannel.com collected 2026-10-02 03:19:01 UTC 15,592 bytes, 457 lines download raw bytes

1"use strict";
2
3/**
4 * Responsive GPT ads.
5 *
6 * GPT renders each ad inside a fixed-size, cross-origin iframe. On narrow
7 * screens a creative wider than its container (e.g. a 320px leaderboard on a
8 * ~300px viewport) gets cut off, because the iframe's content cannot reflow.
9 *
10 * To keep the whole ad visible we scale the rendered iframe down with a CSS
11 * transform so its width fills the ad container and its height follows the
12 * creative's aspect ratio. The served size comes from GPT's `slotRenderEnded`
13 * event; we also rescale on resize and run a fallback pass for ads that may
14 * have rendered before the listener was attached.
15 *
16 * Every GPT placement holds its iframe in one of two containers:
17 *   - `.ad-main`        — the iframe is a direct child. Covers the top
18 *                         leaderboard (parts/ads/ad-top.php), the middle/bottom
19 *                         leaderboards (ad-leaderboard-2.php, ad-bottom.php),
20 *                         in-article ads (ad-in-article.php + single.php),
21 *                         the post-grid rectangle (PostGridView.php) and the
22 *                         sidebar rectangle (ad-sidebar*.php).
23 *   - `.iframe-contain` — in-content "ad" bloks, e.g. the middle of the
24 *                         homepage (blok-party/Views/AdView.php).
25 *
26 * The blok wraps its `.iframe-contain` in an outer `.ad-main`, so that outer
27 * div matches `.ad-main` too — but its real GPT iframe lives in the nested
28 * `.iframe-contain` (matched and scaled on its own). We skip any `.ad-main`
29 * that contains a `.iframe-contain` to avoid sizing against the wrong box and
30 * tracking the same iframe twice.
31 */
32(function () {
33  var ads = []; // { el, width, height }
34
35  // Containers whose direct child is the GPT iframe we scale.
36  var AD_SELECTOR = '.ad-main, .iframe-contain';
37  function isAdContainer(el) {
38    if (!el || typeof el.className !== 'string') {
39      return false;
40    }
41    // Blok in-content ad: the GPT iframe sits directly in `.iframe-contain`.
42    if (el.className.indexOf('iframe-contain') !== -1) {
43      return true;
44    }
45    // Every other placement holds the iframe directly in `.ad-main`. Exclude
46    // the blok's outer `.ad-main` wrapper, which nests a `.iframe-contain`.
47    return el.className.indexOf('ad-main') !== -1 && !el.querySelector('.iframe-contain');
48  }
49  function applyScale(entry) {
50    var el = entry.el;
51    var iframe = el.querySelector('iframe');
52    if (!iframe || !entry.width || !entry.height) {
53      return;
54    }
55    var available = el.clientWidth;
56    if (!available) {
57      return;
58    }
59
60    // Only ever scale down — never blow a small creative up past 1:1.
61    var scale = Math.min(1, available / entry.width);
62
63    // Pin the iframe to the served creative size. GPT sets these as width/height
64    // attributes, but a global responsive-media reset (iframe { height: auto })
65    // overrides the height attribute and collapses the frame to the browser's
66    // 150px iframe default, clipping the creative. An inline style wins over it.
67    // `.iframe-contain iframe` also caps width at 100% of the container; clear
68    // that so the pinned width holds and the transform below scales to fit.
69    iframe.style.maxWidth = 'none';
70    iframe.style.width = entry.width + 'px';
71    iframe.style.height = entry.height + 'px';
72    iframe.style.transformOrigin = 'top center';
73    iframe.style.transform = scale < 1 ? 'scale(' + scale + ')' : '';
74
75    // Reserve the scaled height so the section below doesn't overlap the ad,
76    // and clip the now-empty space left by the transform.
77    el.style.height = Math.ceil(entry.height * scale) + 'px';
78    el.style.overflow = 'hidden';
79  }
80  function track(el, width, height) {
81    if (!el || !width || !height) {
82      return;
83    }
84    ads = ads.filter(function (e) {
85      return e.el !== el;
86    });
87    var entry = {
88      el: el,
89      width: width,
90      height: height
91    };
92    ads.push(entry);
93    applyScale(entry);
94  }
95  function rescaleAll() {
96    for (var i = 0; i < ads.length; i++) {
97      applyScale(ads[i]);
98    }
99  }
100
101  // Primary source of truth: GPT tells us the exact served size per slot.
102  window.googletag = window.googletag || {
103    cmd: []
104  };
105  window.googletag.cmd.push(function () {
106    window.googletag.pubads().addEventListener('slotRenderEnded', function (event) {
107      if (event.isEmpty || !Array.isArray(event.size)) {
108        return;
109      }
110      var el = document.getElementById(event.slot.getSlotElementId());
111      if (!isAdContainer(el)) {
112        return;
113      }
114      var width = event.size[0];
115      var height = event.size[1];
116      // The iframe is appended right after the event fires.
117      window.requestAnimationFrame(function () {
118        track(el, width, height);
119      });
120    });
121  });
122
123  // Fallback: catch any ad that rendered before the listener attached, using
124  // the iframe's own width/height attributes.
125  function initExisting() {
126    var els = document.querySelectorAll(AD_SELECTOR);
127    for (var i = 0; i < els.length; i++) {
128      // `.ad-main` also matches the blok's outer wrapper; skip it so we don't
129      // size against the wrong box or track its nested iframe twice.
130      if (!isAdContainer(els[i])) {
131        continue;
132      }
133      var iframe = els[i].querySelector('iframe');
134      if (!iframe) {
135        continue;
136      }
137      track(els[i], parseInt(iframe.getAttribute('width'), 10), parseInt(iframe.getAttribute('height'), 10));
138    }
139  }
140  if (document.readyState === 'loading') {
141    document.addEventListener('DOMContentLoaded', initExisting);
142  } else {
143    initExisting();
144  }
145  // GPT renders asynchronously; sweep again shortly after load.
146  window.addEventListener('load', function () {
147    window.setTimeout(initExisting, 500);
148  });
149  var resizeTimer;
150  window.addEventListener('resize', function () {
151    window.clearTimeout(resizeTimer);
152    resizeTimer = window.setTimeout(rescaleAll, 150);
153  });
154})();
155"use strict";
156
157jQuery(document).ready(function ($) {
158  /**
159   * This snippet controls the back to top button.
160   */
161
162  var backToTopButton = $("#backToTopButton");
163  $(window).scroll(function () {
164    if ($(window).scrollTop() > 100) {
165      backToTopButton.addClass("show");
166    } else {
167      backToTopButton.removeClass("show");
168    }
169  });
170  backToTopButton.on("click", function (e) {
171    e.preventDefault();
172    $("html, body").animate({
173      scrollTop: 0
174    }, 300);
175  });
176});
177"use strict";
178
179jQuery(function filterButtons($) {
180  var loading_message_html = '<p>Loading...</p>';
181  $('body').on('click', '.js-filter-button', function (e) {
182    e.preventDefault();
183    var target_url = $(this).attr('href');
184    var $container = $(this).closest('[data-filtered-query="post-list"]');
185    var url_parameter = $(this).data('url-parameter');
186    var value = $(this).data('value');
187
188    // uncheck the corresponding filter checkbox
189    $('input[name="' + url_parameter + '[]"][value="' + value + '"]').prop('checked', false);
190    // add the loading message
191
192    $container.html(loading_message_html);
193
194    // execute the ajax request
195
196    $.get(target_url, {}, function (response) {
197      var $response = $(response);
198      var $response_container = $response.find('[data-filtered-query="post-list"]');
199      $container.html($response_container.html());
200    });
201  });
202});
203"use strict";
204
205jQuery(function filteredQuery($) {
206  var loading_message_html = '<p class="post-list-message">Loading...</p>';
207  $('[data-filtered-query=container]').each(function (i, el) {
208    var $filtered_query_container = $(el);
209    var container_id = $filtered_query_container.attr('id');
210    var ajax_url = $filtered_query_container.data('url');
211    var $filter_inputs = $filtered_query_container.find('[data-filtered-query=filter]');
212    var $post_list_containers = $filtered_query_container.find('[data-filtered-query=post-list]');
213    var last_request_time;
214
215    // Todo: Debounce this function
216    $filter_inputs.on('change', runFilteredQuery);
217
218    // Todo: Check if pagination works the same with multiple containers
219    var topPagination = document.querySelector('[data-pagination="top"]');
220    if (topPagination !== null) {
221      var topPaginationLocation = topPagination.getBoundingClientRect().top;
222      $post_list_containers.on('click', 'a.page-numbers', function (e) {
223        e.preventDefault();
224        window.scrollTo({
225          left: 0,
226          top: topPaginationLocation,
227          behavior: 'smooth'
228        });
229        loadPaginationLink($(this).attr('href'));
230      });
231    }
232    function runFilteredQuery() {
233      var request_time = Date.now();
234      var filters_parameters = getFiltersParameters();
235      console.log('getFiltersParameters', filters_parameters);
236      // Mark the last request time, so that we only use the latest response
237      // if the ajax requests come back out of order.
238      last_request_time = request_time;
239      addLoadingMessage();
240      $.get(ajax_url, filters_parameters, function (response) {
241        // If the response is not the latest one, ignore it.
242        if (request_time !== last_request_time) {
243          return;
244        }
245        loadPostsFromResponse(response);
246      });
247    }
248    function getFiltersParameters() {
249      var filters_parameters = {};
250      $filter_inputs.each(function (i, el) {
251        var $el = $(el);
252        var name = $el.attr('name');
253        var value = $el.val();
254        if ($el.prop('checked')) {
255          switch ($el.attr('type')) {
256            case 'checkbox':
257              filters_parameters[name] = filters_parameters[name] || [];
258              filters_parameters[name].push(value);
259              break;
260            case 'radio':
261              filters_parameters[name] = value;
262              break;
263          }
264        }
265      });
266      return filters_parameters;
267    }
268    function loadPostsFromResponse(response) {
269      var $response_wrapper = $(response);
270      var $response_container = $response_wrapper.find('#' + container_id);
271      var $response_post_list = $response_container.find('[data-filtered-query=post-list]');
272      var $sidebar2 = $("#sidebar-2");
273      $post_list_containers.each(function (index, el) {
274        var $this_post_list = $(el);
275        var $corresponding_post_list = $response_post_list.eq(index);
276        /** 
277         * CMT-457: Remove second 'loading' message if there are fewer than 5 posts returned from selected filter.
278         * Author: Creed Development
279         */
280        if ($corresponding_post_list.html() === undefined || $corresponding_post_list.html() == "") {
281          // hide the loading message;
282          $this_post_list.hide();
283          $sidebar2.hide();
284        } else {
285          $this_post_list.show();
286          $sidebar2.show();
287        }
288        $this_post_list.html($corresponding_post_list.html());
289      });
290    }
291    function loadPaginationLink(target_url) {
292      addLoadingMessage();
293      $.get(target_url, {}, loadPostsFromResponse);
294    }
295    function addLoadingMessage() {
296      $post_list_containers.html(loading_message_html);
297    }
298  });
299});
300"use strict";
301
302//== SHOW DROPDOWN IN MENU
303
304var navItems = document.querySelectorAll('#navMenu .nav-item');
305navItems.forEach(function (navItem) {
306  var subMenu = navItem.getElementsByClassName('sub-menu')[0];
307  if (subMenu) {
308    navItem.addEventListener('click', function () {
309      var isVisible = subMenu.classList.contains('visible');
310      if (isVisible) {
311        subMenu.classList.remove('visible');
312        navItem.classList.remove('open');
313      } else {
314        subMenu.classList.add('visible');
315        navItem.classList.add('open');
316      }
317    });
318    navItem.addEventListener('mouseenter', function () {
319      subMenu.classList.add('visible');
320      navItem.classList.add('open');
321    });
322    navItem.addEventListener('mouseleave', function () {
323      subMenu.classList.remove('visible');
324      navItem.classList.remove('open');
325    });
326  }
327});
328"use strict";
329
330/**
331 * This snippet is for the side nav menu.
332 * It toggles the sub-menu when the nav item is clicked.
333 */
334
335var sideNavItems = document.querySelectorAll('#mainNav .nav-item');
336var prevItem = null;
337sideNavItems.forEach(function (navItem) {
338  var subMenu = navItem.getElementsByClassName('sub-menu')[0];
339  if (subMenu) {
340    navItem.addEventListener('click', function () {
341      var isVisible = subMenu.classList.contains('visible');
342      if (!prevItem) {
343        prevItem = navItem;
344      } else if (prevItem !== navItem) {
345        prevItem.classList.remove('open');
346        prevItem.getElementsByClassName('sub-menu')[0].classList.remove('visible');
347        prevItem = navItem;
348      }
349      if (isVisible) {
350        subMenu.classList.remove('visible');
351        navItem.classList.remove('open');
352      } else {
353        subMenu.classList.add('visible');
354        navItem.classList.add('open');
355      }
356    });
357  }
358});
359
360/**
361 * This snippet is for the mobile menu.
362 * It toggles the nav drawer menu when the burger menu is clicked.
363 */
364
365var burgerMenu = document.getElementById("burgerMenu");
366var navDrawer = document.getElementById("navDrawer");
367var mainNav = document.getElementById("mainNav");
368var menuShowing = false;
369var toggleMenu = function toggleMenu() {
370  navDrawer.classList.toggle("visible");
371  burgerMenu.classList.toggle("close");
372  menuShowing = !menuShowing;
373  if (prevItem) {
374    prevItem.classList.remove('open');
375    prevItem.getElementsByClassName('sub-menu')[0].classList.remove('visible');
376  }
377};
378burgerMenu.onclick = function () {
379  return toggleMenu();
380};
381window.addEventListener("click", function (event) {
382  if (menuShowing && !burgerMenu.contains(event.target) && !mainNav.contains(event.target)) {
383    toggleMenu();
384  }
385});
386"use strict";
387
388/**
389 * Transition the pull-quote if exists
390 */
391var pullQuote = document.querySelector('.company-profile__pull-quote');
392if (pullQuote) {
393  var observer = new IntersectionObserver(function (entries) {
394    entries.forEach(function (entry) {
395      if (entry.isIntersecting) {
396        pullQuote.classList.add('active');
397      }
398    });
399  });
400  observer.observe(pullQuote);
401}
402"use strict";
403
404/**
405 * Functionality for share post link
406 */
407
408var shareCopy = document.querySelectorAll(".share-copy");
409shareCopy.forEach(function (element) {
410  element.addEventListener("click", function () {
411    var copyText = element.getAttribute("data-tc-copyurl");
412    var copyTarget = element.getAttribute("data-tc-copytarget");
413    navigator.clipboard.writeText(copyText);
414    var myModal = new bootstrap.Modal(document.getElementById('copyModal-' + copyTarget));
415    myModal.show();
416  });
417});
418
419/**
420 * Toggle visibility of share links
421 */
422
423var shareToggle = document.querySelectorAll(".share-links-button__toggle");
424shareToggle.forEach(function (element) {
425  var visible = false;
426  var shareLinks = element.nextElementSibling;
427  element.addEventListener("click", function () {
428    if (visible) {
429      shareLinks.classList.remove('is-visible');
430      visible = false;
431    } else {
432      shareLinks.classList.add('is-visible');
433      visible = true;
434    }
435  });
436});
437"use strict";
438
439/**
440 * Close the Subscribe CTA popup
441 */
442
443var subscribeCTAStatus = sessionStorage.getItem('subscribeCTA');
444var subscribeCTA = document.getElementById('subscribeCTA');
445var closeSubscribeCTA = document.getElementById('closeSubscribeCTA');
446if (subscribeCTA) {
447  if (subscribeCTAStatus !== 'hidden') {
448    setTimeout(function () {
449      subscribeCTA.classList.remove('hidden');
450    }, 5000);
451  }
452  ;
453  closeSubscribeCTA.addEventListener('click', function () {
454    subscribeCTA.classList.add('hidden');
455    sessionStorage.setItem('subscribeCTA', 'hidden');
456  });
457}

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.