PageSourceSearch

https://rcpsg.ac.uk/themes/ud/js/script.js?v=1.x

js rcpsg.ac.uk collected 2026-10-02 04:11:03 UTC 16,909 bytes, 433 lines download raw bytes

1// Global Javascript
2
3var rcpsgUI = (function (jQuery) {
4
5  //---------- Main Nav Handler
6  function mainNav() {
7    //--------- Desktop nav handler
8    if(jQuery(window).width() > 992) {
9      jQuery(document).on('mouseenter focusin', '.mnav-dropdown', function () {
10        jQuery(this).closest('li').addClass('mnav-dd-opened');
11      }).on('mouseleave focusout', '.mnav-dropdown', function () {
12        jQuery('.mnav-dd-opened').removeClass('mnav-dd-opened');
13      });
14
15
16    }
17
18    //--------- Mobile nav handler
19    jQuery(document).on('click','.mm-trigger',function (){
20      jQuery('html').toggleClass('mm-opened');
21    })
22    jQuery(document).on('click', '.mobile-dd-trigger', function () {
23
24      let parent = jQuery(this).parent('li');
25      if(parent.hasClass('mnav-dd-opened')){
26        parent.removeClass('mnav-dd-opened')
27        parent.find('.mnav-dropdown').slideUp()
28      } else {
29        parent.addClass('mnav-dd-opened')
30        parent.find('.mnav-dropdown').slideDown()
31      }
32
33      parent.siblings().removeClass('mnav-dd-opened')
34      parent.siblings().find('.mnav-dropdown').slideUp()
35    })
36  }
37
38  //---------- Site Search Handler
39  function siteSearch() {
40    jQuery(document).on('click','.site-search--trigger', function (e){
41
42
43      jQuery(this).toggleClass('search-active')
44      jQuery('.ss-cnt').toggleClass('ss-input-active');
45        if (document.cookie.indexOf("rcpsgbanner=") < 0) {
46            jQuery('.ss-cnt').toggleClass('banner-active');
47        }
48
49      jQuery(this).attr('aria-expanded', function (i, attr) {
50        return attr == 'false' ? 'true' : 'false';
51      })
52
53      if(jQuery(window).width() > 992){
54        jQuery(this).hasClass('search-active')?
55          jQuery('.ss-search .form-search').focus() : jQuery(this).focus()
56
57        jQuery(document).on('focusout','.ss-search .form-submit', function (){
58          jQuery('.site-search--trigger').focus()
59          jQuery('.site-search--trigger').removeClass('search-active').attr('aria-expanded','false')
60          jQuery('.ss-cnt').removeClass('ss-input-active')
61        })
62      }
63    })
64    jQuery("#edit-keys").attr('placeholder','Search...').attr('autocomplete','off')
65  }
66
67  //---------- Back to top button
68  function backToTopBtnHandler() {
69    jQuery(document).on('click','.btt', function (e) {
70      jQuery("html, body").animate({ scrollTop: 0 }, "slow");
71
72    })
73
74    // Handle Enter key press
75    jQuery(document).on('keydown', '.btt', function (e) {
76      if (e.key === 'Enter' || e.keyCode === 13) {
77        jQuery("html, body").animate({ scrollTop: 0 }, "slow");
78        jQuery('.main-logo').focus();
79      }
80    });
81  }
82
83
84  //---------- Video Thumbnail
85  function videoThumbnailHandler() {
86    jQuery('.video-comprise').each(function() {
87      let videoIframe = jQuery(this).find('.v-video iframe');
88      let videoSrc = videoIframe.data('src') || videoIframe.attr('src');
89      let videoIdMatch = videoSrc.match(/(?:youtube\.com.*(?:\?v=|\/embed\/)|youtu\.be\/)(.{11})/);
90      if (videoIdMatch) {
91        let videoId = videoIdMatch[1];
92        let videoImage = `https://img.youtube.com/vi/${videoId}/maxresdefault.jpg`;
93
94        // Attach the thumbnail image
95        jQuery(this).find('.v-video').append(
96          `<img class="v-thumbnail" src="${videoImage}" loading="lazy" alt="Video thumbnail">`
97        );
98      }
99      videoIframe.attr('allow','autoplay')
100    });
101  }
102
103  //---------- Video Play
104  function videoPlayHandler() {
105    jQuery(document).on('click', '.v-video-play-btn', function (e) {
106      e.preventDefault();
107      let videoContainer = jQuery(this).closest('.v-video');
108      videoContainer.addClass('video-played');
109
110      var src = videoContainer.find('iframe').attr('src');
111      videoContainer.find('iframe').attr('src', src + '?rel=0&autoplay=1')
112    })
113  }
114
115  //--------- Tables handler
116  function tablesHandler() {
117    //***** Table wrapper
118    jQuery('.text-content table').wrap('<div class="table-cnt"></div>');
119    jQuery('.text-content table :is(th,td)').attr( 'tabindex', '1')
120    jQuery('.text-content table tr th').attr('scope','col');
121    jQuery('.table-cnt').each(function () {
122      let $table = jQuery(this).find('table');
123      // Compare the widths
124      $table.outerWidth() > jQuery(this).outerWidth() && jQuery(this).addClass('scrollable-table');
125    });
126
127
128
129    jQuery(".text-content table").each(function() {
130      var table = jQuery(this);
131      var headers = [];
132
133      // Get the column headings from the first row of the thead
134      table.find("thead tr:first th").each(function() {
135        headers.push(jQuery(this).text().trim()); // Store header text
136      });
137
138      // Assign data-heading attributes to each cell in the tbody
139      table.find("tbody tr").each(function() {
140        jQuery(this).find("td").each(function(index) {
141          if (headers[index]) {
142            jQuery(this).attr("data-heading", headers[index]);
143          }
144        });
145      });
146    });
147  }
148
149
150  //--------- Accordions handler
151  function accordionsHandler() {
152    jQuery(document).on('click', '.acc-item-trigger',function (){
153      console.log(jQuery(this))
154      jQuery(this).siblings('.acc-item-content').slideToggle()
155      jQuery(this).closest('.acc-item').toggleClass('acc-selected');
156      jQuery(this).attr('aria-expanded', function (i, attr) {
157        return attr == 'false' ? 'true' : 'false';
158      })
159    })
160  }
161
162  //--------- External links handler
163  function addAriaToExternalLinks() {
164    const currentHost = location.hostname;
165
166    const externalCtaLinks = jQuery('.cta-btn[href^="http"]').filter(function () {
167      return new URL(this.href).hostname !== currentHost;
168    });
169
170    const externalParagraphLinks = jQuery('p > a[href^="http"]').filter(function () {
171      return new URL(this.href).hostname !== currentHost;
172    });
173
174    // Exit early if no external links found
175    if (externalCtaLinks.length === 0 && externalParagraphLinks.length === 0) {
176      return;
177    }
178
179    externalCtaLinks.each(function () {
180      jQuery(this)
181        .attr('aria-label', 'Opens external link in a new tab')
182        .attr('target', '_blank');
183    });
184
185    externalParagraphLinks.each(function () {
186      jQuery(this).attr('target', '_blank');
187    });
188  }
189
190
191
192
193  //--------- Zoom level detection
194  // function detectZoomHandler() {
195  //   function isMobileDevice() {
196  //     return /Mobi|Android|iPhone|iPad|iPod/i.test(navigator.userAgent);
197  //   }
198  //
199  //   function detectZoom() {
200  //     if (isMobileDevice()) {
201  //       jQuery('html').removeClass('zoomed-in');
202  //       return;
203  //     }
204  //
205  //     const dpr = window.devicePixelRatio || 1;
206  //     const zoomPercent = Math.round(dpr * 100);
207  //
208  //     if (zoomPercent >= 200) {
209  //       jQuery('html').addClass('zoomed-in');
210  //       jQuery('.main-nav-side').insertBefore('.main-nav');
211  //
212  //       jQuery('.main-nav > nav > ul > li:last-child > a').off('blur').on('blur', function () {
213  //         jQuery('.mm-trigger').focus();
214  //       });
215  //     } else {
216  //       jQuery('html').removeClass('zoomed-in');
217  //       jQuery('.main-nav').insertBefore('.main-nav-side');
218  //     }
219  //   }
220  //
221  //   jQuery(document).ready(detectZoom);
222  //   jQuery(window).on('resize', detectZoom);
223  // }
224  function loadOomiUserSection() {
225
226    fetch('/udcustom/cart-count')
227      .then(response => {
228        return response.json();
229      })
230      .then(data => {
231
232        const container = document.getElementById('oomi-user-section');
233        if (!container) {
234          console.warn('Could not find #oomi-user-section in the DOM');
235          return;
236        }
237
238        if (data.cart_count != null) {
239          container.innerHTML = `
240          <a class="cart" href="https://community.rcpsg.ac.uk/cart/index">
241            <svg xmlns="http://www.w3.org/2000/svg" width="24" height="25" viewBox="0 0 24 25" fill="none">
242              <path d="M9.75 11.5518C9.94891 11.5518 10.1397 11.6308 10.2803 11.7714C10.421 11.9121 10.5 12.1028 10.5 12.3018V16.3018C10.5 16.5007 10.421 16.6914 10.2803 16.8321C10.1397 16.9727 9.94891 17.0518 9.75 17.0518C9.55109 17.0518 9.36032 16.9727 9.21967 16.8321C9.07902 16.6914 9 16.5007 9 16.3018V12.3018C9 12.1028 9.07902 11.9121 9.21967 11.7714C9.36032 11.6308 9.55109 11.5518 9.75 11.5518ZM15 12.3018C15 12.1028 14.921 11.9121 14.7803 11.7714C14.6397 11.6308 14.4489 11.5518 14.25 11.5518C14.0511 11.5518 13.8603 11.6308 13.7197 11.7714C13.579 11.9121 13.5 12.1028 13.5 12.3018V16.3018C13.5 16.5007 13.579 16.6914 13.7197 16.8321C13.8603 16.9727 14.0511 17.0518 14.25 17.0518C14.4489 17.0518 14.6397 16.9727 14.7803 16.8321C14.921 16.6914 15 16.5007 15 16.3018V12.3018Z" fill="#395B73"/>
243              <path d="M10.68 2.18818C10.8428 2.30229 10.9536 2.47634 10.9881 2.6721C11.0226 2.86785 10.9779 3.0693 10.864 3.23218L8.365 6.80218H15.635L13.135 3.23218C13.021 3.06907 12.9764 2.86734 13.0111 2.67136C13.0458 2.47539 13.1569 2.30122 13.32 2.18718C13.4831 2.07313 13.6848 2.02856 13.8808 2.06325C14.0768 2.09795 14.251 2.20907 14.365 2.37218L17.465 6.80218H19.75C20.3467 6.80218 20.919 7.03923 21.341 7.46119C21.7629 7.88314 22 8.45544 22 9.05218V9.83718C22 10.1722 21.9253 10.503 21.7812 10.8054C21.637 11.1078 21.4272 11.3742 21.167 11.5852L20.004 12.5282L19.201 18.8362C19.1319 19.3793 18.8671 19.8787 18.4562 20.2406C18.0453 20.6025 17.5165 20.8022 16.969 20.8022H7.031C6.48345 20.8022 5.95469 20.6025 5.54381 20.2406C5.13292 19.8787 4.86811 19.3793 4.799 18.8362L3.995 12.5282L2.833 11.5852C2.57278 11.3742 2.36296 11.1078 2.21884 10.8054C2.07473 10.503 1.99996 10.1722 2 9.83718V9.05218C2 8.45544 2.23705 7.88314 2.65901 7.46119C3.08097 7.03923 3.65326 6.80218 4.25 6.80218H6.534L9.636 2.37218C9.75011 2.20942 9.92417 2.09862 10.1199 2.06412C10.3157 2.02962 10.5171 2.07424 10.68 2.18818ZM19.75 8.30218H4.25C4.05109 8.30218 3.86032 8.3812 3.71967 8.52185C3.57902 8.6625 3.5 8.85327 3.5 9.05218V9.83718C3.5 10.0632 3.602 10.2772 3.778 10.4202L5.174 11.5522C5.32376 11.6739 5.42082 11.8487 5.445 12.0402L6.287 18.6472C6.31011 18.8282 6.39842 18.9945 6.53537 19.1151C6.67232 19.2357 6.84853 19.3022 7.031 19.3022H16.969C17.1515 19.3022 17.3277 19.2357 17.4646 19.1151C17.6016 18.9945 17.6899 18.8282 17.713 18.6472L18.554 12.0402C18.5784 11.8486 18.6759 11.6737 18.826 11.5522L20.222 10.4202C20.3088 10.3498 20.3789 10.261 20.427 10.1601C20.4751 10.0593 20.5 9.94893 20.5 9.83718V9.05218C20.5 8.85327 20.421 8.6625 20.2803 8.52185C20.1397 8.3812 19.9489 8.30218 19.75 8.30218Z" fill="#395B73"/>
244            </svg>
245            <span>${data.cart_count}</span>
246          </a>
247          <a href="https://community.rcpsg.ac.uk/Account/Dashboard" target="_blank" aria-label="Dashboard" class="dashboard-btn">
248            <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" viewBox="0 0 24 24" fill="none"  stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
249              <path d="M20 21v-2a4 4 0 0 0-4-4H8a4 4 0 0 0-4 4v2"/><circle cx="12" cy="7" r="4"/>
250            </svg>
251            </a>
252            <a href="https://community.rcpsg.ac.uk/account/logout" target="_blank" class="user-btn">Log out</a>
253        `;
254        } else {
255          container.innerHTML = `
256          <a href="https://sso.rcpsg.ac.uk/" class="user-btn">Log in</a>
257          <a href="/membership" target="_blank" class="user-btn user-btn-gray" data-position="top right" data-intent="join">Join us</a>
258        `;
259        }
260      })
261      .catch(error => {
262        console.error('Error in fetch /udcustom/cart-count:', error);
263      });
264  }
265
266    function siteBanner() {
267        if (document.cookie.indexOf("rcpsgbanner=") < 0) {
268            jQuery('.site-banner').css('display','block');
269            jQuery('body').addClass('banner-visible');
270        }
271        jQuery('.site-banner__link').click(function(e){
272            e.preventDefault();
273            var expiryDate = new Date();
274            expiryDate.setMonth(expiryDate.getMonth() + 1);
275            document.cookie = 'rcpsgbanner=1; expires=' + expiryDate.toGMTString() + ';' ;
276            jQuery('.site-banner').hide();
277            jQuery('body').removeClass('banner-visible');
278        });
279    }
280
281  //--------- Multiple Download Files Handler
282  function MultiDownloadHandler() {
283    jQuery('.para-multiple-file-downloads').each(function () {
284      const $container = jQuery(this);
285      const $downloads = $container.find('.download-wrapper');
286
287      if ($downloads.length > 4) {
288
289        $downloads.slice(4).hide(); // Hide all after the 4th
290
291        const $btn = $container.find('.show-download-files');
292
293        $btn.on('click', function () {
294          $container.toggleClass('download-files-shown');
295
296          const isShown = $container.hasClass('download-files-shown');
297
298          $downloads.slice(4).toggle(isShown);
299
300          $btn.find('.show-download-files--text').text(isShown ? 'Show less' : 'Show all');
301        });
302      } else {
303        // Hide button if 4 or fewer items
304        $container.find('.show-download-files').hide();
305      }
306    });
307  }
308
309
310  //--------- Image Gallery component
311  function galleryComponentHandler() {
312    // Check if the gallery component exists
313    if (!jQuery('.para-gallery').length) {
314      return; // Exit early if gallery component is not on the page
315    }
316
317    // Modal handler
318    const modal = document.getElementById('imageModal');
319    if (!modal) return;
320
321    const modalImg = modal.querySelector('#modalImage');
322    const modalTitle = modal.querySelector('#modalTitle');
323    const modalDesc = modal.querySelector('#modalDesc');
324    const closeBtn = modal.querySelector('.modal-close');
325    const overlay = modal.querySelector('.modal-overlay');
326
327    if (!modalImg || !modalTitle || !modalDesc || !closeBtn || !overlay) return;
328
329    // Optional: Add a loading spinner inside the modal
330    const spinner = document.createElement('div');
331    spinner.className = 'modal-spinner';
332    spinner.innerText = 'No image to show';
333    modal.querySelector('.modal-content').appendChild(spinner);
334    spinner.style.display = 'none';
335
336    jQuery('.gallery-card-nolink').each(function () {
337      jQuery(this).on('click', function () {
338        const img = this.querySelector('img');
339        const title = this.querySelector('h3')?.innerText || '';
340        const desc = this.querySelector('p')?.innerText || '';
341
342        modalImg.src = '';
343        modalImg.alt = '';
344        modalTitle.innerText = '';
345        modalDesc.innerText = '';
346
347        modal.removeAttribute('hidden');
348        spinner.style.display = 'block';
349
350        const newImg = new Image();
351        newImg.onload = function () {
352          modalImg.src = newImg.src;
353          modalImg.alt = img.alt;
354          modalTitle.innerText = title;
355          modalDesc.innerText = desc;
356          spinner.style.display = 'none';
357        };
358        newImg.src = img.src;
359
360        closeBtn.focus();
361      });
362    });
363
364    function closeModal() {
365      modal.setAttribute('hidden', true);
366      modalImg.src = '';
367    }
368
369    closeBtn.addEventListener('click', closeModal);
370    overlay.addEventListener('click', closeModal);
371    document.addEventListener('keydown', function (e) {
372      if (e.key === 'Escape') {
373        closeModal();
374      }
375    });
376
377    // View more button handler
378    jQuery('.para-gallery').each(function () {
379      const galleryCard = jQuery(this).find('.gallery-card');
380      const _thisButton = jQuery(this).find('.toggle-gallery-btn');
381
382      if (galleryCard.length > 4) {
383        _thisButton.show();
384      }
385    });
386
387    jQuery(document).on('click', '.toggle-gallery-btn', function () {
388      const btn = jQuery(this);
389      const closestCardsCnt = btn.siblings('.gallery-cards');
390      btn.text(btn.text() === 'Show more' ? 'Show less' : 'Show more');
391      btn.closest('.para-gallery').find('.gc-hidden').toggleClass('gc-shown');
392      if(jQuery(window).width() > 992) {
393        jQuery('html, body').animate({ scrollTop: closestCardsCnt.offset().top - 100 }, 'slow');
394      }
395    });
396  }
397
398
399  return {
400    mainNav:mainNav,
401    siteSearch:siteSearch,
402    backToTopBtnHandler:backToTopBtnHandler,
403    videoThumbnailHandler:videoThumbnailHandler,
404    videoPlayHandler:videoPlayHandler,
405    tablesHandler:tablesHandler,
406    accordionsHandler:accordionsHandler,
407    addAriaToExternalLinks:addAriaToExternalLinks,
408    // detectZoomHandler:detectZoomHandler,
409    loadOomiUserSection:loadOomiUserSection,
410    siteBanner:siteBanner,
411    MultiDownloadHandler:MultiDownloadHandler,
412    galleryComponentHandler:galleryComponentHandler
413  }
414}(jQuery));
415
416
417jQuery(document).ready(function () {
418  rcpsgUI.mainNav();
419  rcpsgUI.siteSearch();
420  rcpsgUI.backToTopBtnHandler();
421  rcpsgUI.videoThumbnailHandler();
422  rcpsgUI.videoPlayHandler();
423  rcpsgUI.tablesHandler();
424  rcpsgUI.accordionsHandler();
425  rcpsgUI.addAriaToExternalLinks();
426  // rcpsgUI.detectZoomHandler();
427  rcpsgUI.loadOomiUserSection();
428  rcpsgUI.siteBanner();
429  rcpsgUI.MultiDownloadHandler();
430  rcpsgUI.galleryComponentHandler();
431})
432
433

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.