PageSourceSearch

https://www.fhf.fr/themes/custom/fhf_theme/js/main.js?v=1.2

js fhf.fr collected 2026-09-24 09:25:53 UTC 24,203 bytes, 821 lines download raw bytes

1(function ($, Drupal, window, document) {
2
3  /**
4   * Sticky header
5   */
6  Drupal.behaviors.fhfStickyHeader = {
7    attach: function (context) {
8      if (context !== document) {
9        return;
10      }
11      var body = $('body', context);
12
13      $(window).on('scroll', function() {
14        if ($(this).scrollTop() > 153) {
15          body.addClass('has-sticky');
16        } else {
17          body.removeClass('has-sticky');
18        }
19      });
20    }
21  };
22
23  /**
24   * Search on header
25   */
26  Drupal.behaviors.fhfSearchHeader = {
27    attach: function (context) {
28      if (context !== document) {
29        return;
30      }
31      // We may have multiple search forms in one page
32      $('.form-autocomplete', context).each((index, input) => {
33        let searchInput = $(input);
34        let parent = searchInput.parent();
35        if (searchInput.length) {
36          searchInput.autocomplete({
37            appendTo: parent,
38            open: function () {
39              searchInput.addClass('is-focused');
40              searchInput.siblings('ul').wrap('<div class="ui-autocomplete--wrapper"></div>');
41            },
42            close: function () {
43              searchInput.removeClass('is-focused');
44              searchInput.siblings().find('ul').unwrap();
45            }
46          });
47        }
48      });
49    }
50  };
51
52  /**
53   * ScrollTop
54   */
55  Drupal.behaviors.fhfTarteaucitronPanel = {
56    attach: function (context) {
57      if (context !== document) {
58        return;
59      }
60      $('.tarteaucitron-panel', context).click(function () {
61        if (tarteaucitron) {
62          tarteaucitron.userInterface.openPanel();
63        }
64      });
65    }
66  };
67
68  /**
69   * ScrollTop
70   */
71  Drupal.behaviors.fhfScrollTop = {
72    attach: function (context) {
73      if (context !== document) {
74        return;
75      }
76      $('.js-scroll-top', context).each(function () {
77        $(window).scroll(function(){
78          var st = $(this).scrollTop();
79          if (st > 50){
80            $('.js-scroll-top').fadeIn(200);
81          } else {
82            $('.js-scroll-top').fadeOut(200);
83          }
84        });
85
86        $(this).on('click', function () {
87          $('html,body').animate({scrollTop: 0}, 'fast', 'linear');
88        });
89      });
90    }
91  };
92
93  /**
94   * Custom select
95   */
96  Drupal.behaviors.fhfCustomSelect = {
97    attach: function (context) {
98      once('sumo-select', 'select', context).forEach(function (element) {
99        var $select = $(element);
100        var placeholder = $select.attr('data-placeholder') || 'Sélectionner';
101
102        $select.SumoSelect({
103          placeholder: placeholder,
104          selectAll: true,
105          forceCustomRendering: true,
106          locale: ['OK', 'Annuler', 'Tout'],
107          captionFormatAllSelected: 'Tous sélectionnés'
108        });
109      });
110
111      // Change "Select all" label for lists' date filter
112      once(
113        'sumo-select-date-filter',
114        '.views-exposed-form .js-form-item-created-year select',
115        context
116      ).forEach(function (element) {
117        var $select = $(element);
118        var placeholder = $select.attr('data-placeholder') || 'Sélectionner';
119
120        if (element.sumo) {
121          element.sumo.unload();
122        }
123
124        $select.SumoSelect({
125          placeholder: placeholder,
126          selectAll: true,
127          locale: ['OK', 'Annuler', 'Toutes les dates'],
128          captionFormatAllSelected: 'Tous sélectionnés'
129        });
130      });
131    }
132  };
133
134  /**
135   * Sticky nav with anchors - scrollspy
136   */
137  Drupal.behaviors.fhfScrollSpy = {
138    attach: function (context) {
139      if (context !== document) {
140        return;
141      }
142
143
144      var body = $('body');
145      var menuLi = $('.nav-anchors li', context);
146      var menu = $('.nav-anchors', context);
147      var menuNavRight = $('.nav-right.nav-bottom-list', context);
148      var mainDiv = $('.region.region-content', context);
149      mainDiv.before(menuNavRight);
150
151      setTimeout(() => {
152        var findHeader = true;
153        if(!body.hasClass('page-node-type-storytelling')){
154          var sectionParagraph = $('[data-nav]', context);
155          if (menuLi.length) {
156            body.attr('data-bs-spy', 'scroll');
157            body.attr('data-bs-target', '#block-content-summary-nav');
158            body.attr('data-bs-offset', 100);
159            if (sectionParagraph.length) {
160              sectionParagraph.each(function (index) {
161                $(this).attr('id', `section-${index}`);
162                menuLi.eq(index).find('a').attr('href', `#section-${index}`);
163                findHeader = false;
164                index++;
165              });
166            }
167            menuNavRight.css("opacity", "1");
168          }
169        }
170
171        if(findHeader) {
172          var headerItems = $('article h2, .taxonomy-term > h2', context);
173          $('.nav-anchors ul').remove();
174          if (headerItems.length > 0) {
175            if ($('.nav-anchors > div > ul.links').length === 0) {
176              menu.prepend("<ul class='links'></ul>");
177              var menuUl = $('.nav-anchors > ul.links');
178              headerItems.each(function (index) {
179                const id = $(this).attr('id');
180                if (id === undefined) {
181                  const text = headerItems[index].innerText.trim();
182                  $(this).attr('id', `section-${index}`);
183                  menuUl.append("<li><a class='nav-link' href=#section-" + index + ">" + text + "</a></li>");
184                  index++;
185                }
186              });
187              menuNavRight.css("opacity", "1");
188            }
189          }else{
190            $('.nav-anchors').parent().remove();
191          }
192        }
193
194      }, 2000);
195
196    }
197  };
198
199  /**
200   * Sticky nav with anchors - nav-link
201   */
202  Drupal.behaviors.fhfScrollNavLink = {
203    attach: function (context) {
204      if (context !== document) {
205        return;
206      }
207      var navLink = $('.nav-anchors .nav-link', context);
208      if (navLink.length) {
209        navLink.click(function(e) {
210          e.preventDefault();
211          var href = $(this).attr('href');
212          $('html, body').animate({
213            scrollTop: $(`${href}`).offset().top - 150
214          }, 300);
215        });
216      }
217    }
218  };
219
220  /**
221   * Tooltips
222   */
223  Drupal.behaviors.fhfTooltip = {
224    attach: function (context) {
225      if (context !== document) {
226        return;
227      }
228      var tooltipTriggerList = [].slice.call(context.querySelectorAll('[data-bs-toggle="tooltip"]'));
229
230      if (tooltipTriggerList) {
231        var tooltipList = tooltipTriggerList.map(function (tooltipTriggerEl) {
232          return new bootstrap.Tooltip(tooltipTriggerEl);
233        });
234      }
235    }
236  };
237
238  /**
239   * Tooltips
240   */
241  Drupal.behaviors.fhfPopover = {
242    attach: function (context) {
243      if (context !== document) {
244        return;
245      }
246      var popoverTriggerList = [].slice.call(context.querySelectorAll('[data-bs-toggle="popover"]'));
247
248      if (popoverTriggerList) {
249        var popoverList = popoverTriggerList.map(function (popoverTriggerEl) {
250          return new bootstrap.Popover(popoverTriggerEl);
251        });
252      }
253    }
254  };
255
256  /**
257   * Table wrapper
258   */
259  Drupal.behaviors.fhfTableWrapper = {
260    attach: function (context) {
261      if (context !== document) {
262        return;
263      }
264      var wrapper = '<div class="table-wrapper"></div>';
265      $('.article__content table', context).each(function () {
266        $(this).wrap(wrapper);
267      });
268    }
269  };
270
271  /**
272   * Mobile slider
273   */
274  Drupal.behaviors.fhfMobileSlider = {
275    attach: function (context) {
276      if (context !== document) {
277        return;
278      }
279      $('.paragraph--type--block-main-events .view-content', context).addClass('mobile-slider js-mobile-slider');
280      $('.view-id-seach.view-display-id-block_similar_content .row', context).addClass('mobile-slider js-mobile-slider');
281      var mobileSlider = $('.js-mobile-slider', context);
282      var mobileSliderOptions = {
283        autoWidth: true,
284        margin: 20,
285        dots: false,
286        nav: true,
287        navText : ["<span class='fhficon fhficon-angle-left'></span>","<span class='fhficon fhficon-angle-right'></span>"]
288      };
289
290      function initMobileSlider() {
291        if ( $(window).width() < 768 ) {
292          mobileSlider.addClass('owl-carousel').owlCarousel(mobileSliderOptions);
293        } else {
294          mobileSlider.removeClass('owl-carousel').trigger('destroy.owl.carousel');
295        }
296      }
297
298      initMobileSlider();
299
300      $(window).resize(function() {
301        initMobileSlider();
302      });
303    }
304  };
305
306  /**
307   * Paragraph carousel (HP top)
308   */
309  Drupal.behaviors.fhfParagraphCarousel = {
310    attach: function (context) {
311      if (context !== document) {
312        return;
313      }
314      $('.paragraph--type--paragraph-carousel .field--type-entity-reference-revisions', context).addClass('owl-carousel').owlCarousel({
315        items: 1,
316        loop: true,
317        autoplay: true,
318        autoplayTimeout: 7000,
319        autoplaySpeed: 1000,
320        autoHeight: true,
321        dots: true,
322        dotsSpeed: 1000,
323        nav: false,
324        navSpeed: 1000,
325        navText : ["<span class='fhficon fhficon-angle-left'></span>","<span class='fhficon fhficon-angle-right'></span>"],
326        responsive : {
327          768 : {
328            nav: true
329          }
330        }
331      });
332    }
333  };
334
335  /**
336   * Recent articles Slider (HP)
337   */
338  Drupal.behaviors.fhfRecentArticlesSlider = {
339    attach: function (context) {
340      if (context !== document) {
341        //return;
342      }
343      $('.main-articles .view-content').addClass('owl-carousel mobile-slider').owlCarousel({
344        loop: false,
345        dots: false,
346        nav: true,
347        margin: 20,
348        navText : ["<span class='fhficon fhficon-angle-left'></span>","<span class='fhficon fhficon-angle-right'></span>"],
349        responsive : {
350          0: {
351            autoWidth: true
352          },
353          768: {
354            autoWidth: false,
355            items: 2
356          },
357          1100: {
358            items: 3
359          }
360        }
361      });
362    }
363  };
364
365  /**
366   * Expertises slider (HP)
367   */
368  Drupal.behaviors.fhfExpertiseSlider = {
369    attach: function (context) {
370      //if (context !== document) {
371        //return;
372      //}
373      $('.main-expertises .view-content', context).addClass('owl-carousel');
374      $('.main-expertises .view-content', context).owlCarousel({
375        autoWidth: true,
376        items: 3,
377        stagePadding: 279,
378        loop: false,
379        dots: false,
380        nav: true,
381        margin: 30,
382        navText : ["<span class='fhficon fhficon-angle-left'></span>","<span class='fhficon fhficon-angle-right'></span>"]
383      });
384
385      $('.js-main-expertise-slider', context).owlCarousel({
386        autoWidth: true,
387        items: 2,
388        stagePadding: 279,
389        loop: false,
390        dots: false,
391        nav: true,
392        margin: 30,
393        navText : ["<span class='fhficon fhficon-angle-left'></span>","<span class='fhficon fhficon-angle-right'></span>"]
394      });
395
396      // Mobile filter dropdown
397      $('.js-main-expertises .option').each(function() {
398        var radio = $(this).prev();
399        var dropDownBtn = $('.js-expertise-active-filter');
400
401        if (!$(this).find('span').length) {
402          $(this).wrapInner('<span></span>');
403        }
404
405        if (radio.is(':checked')) {
406          var label = $(this).html();
407          var id = radio.attr('value');
408
409          dropDownBtn.html(label);
410          dropDownBtn.attr('data-id', id);
411        }
412      });
413    }
414  };
415
416  /**
417   * PublicationsSlider (annuaire)
418   */
419  Drupal.behaviors.fhfAnnuairePublicationsSlider = {
420    attach: function (context) {
421      if (context !== document) {
422        return;
423      }
424      const numChildren = $('.view-id-catalog_item.view-display-id-another_news .view-content .views-row, ' +
425        '.block-catalog__recent-members .content article, ' +
426        '.block-catalog__latest-updated-structures .content article').length; // just an example
427      const isTrueMob = numChildren > 1;
428      const isTrueTab = numChildren > 2;
429      const isTrueDes = numChildren > 3;
430      $('.view-id-catalog_item.view-display-id-another_news .view-content, ' +
431        '.block-catalog__recent-members .content, ' +
432        '.block-catalog__latest-updated-structures .content', context).addClass('owl-carousel mobile-slider').owlCarousel({
433        dots: false,
434        nav: true,
435        margin: 30,
436        navText : ["<span class='fhficon fhficon-angle-left'></span>","<span class='fhficon fhficon-angle-right'></span>"],
437        responsive : {
438          0: {
439            loop: isTrueMob,
440            autoWidth: true
441          },
442          768: {
443            loop: isTrueTab,
444            autoWidth: false,
445            items: 2
446          },
447          1100: {
448            loop: isTrueDes,
449            items: 3
450          }
451        }
452      });
453    }
454  };
455
456  /**
457   * FHF-data Slider
458   */
459  Drupal.behaviors.fhfDataSlider = {
460    attach: function (context) {
461      if (context !== document) {
462        return;
463      }
464      const numChildren = $('.view-display-id-fhf_data_news .view-content .views-row').length; // just an example
465      const isTrueMob = numChildren > 1;
466      const isTrueTab = numChildren > 2;
467      const isTrueDes = numChildren > 3;
468      $('.view-display-id-fhf_data_news .view-content', context).addClass('owl-carousel mobile-slider').owlCarousel({
469        loop: true,
470        dots: false,
471        nav: true,
472        margin: 30,
473        navText : ["<span class='fhficon fhficon-angle-left'></span>","<span class='fhficon fhficon-angle-right'></span>"],
474        responsive : {
475          0: {
476            loop: isTrueMob,
477            autoWidth: true
478          },
479          768: {
480            loop: isTrueTab,
481            autoWidth: false,
482            items: 2
483          },
484          1100: {
485            loop: isTrueDes,
486            items: 3
487          }
488        }
489      });
490    }
491  };
492
493  /**
494   * offre-emploi candidatez slider
495   */
496  Drupal.behaviors.fhfoffresHomeSlider = {
497    attach: function (context) {
498      if (context !== document) {
499        return;
500      }
501      $('.paragraph--type--offers__hot-job-offers .view-content').addClass('owl-carousel mobile-slider').owlCarousel({
502        loop: false,
503        dots: false,
504        nav: true,
505        margin: 20,
506        navText : ["<span class='fhficon fhficon-angle-left'></span>","<span class='fhficon fhficon-angle-right'></span>"],
507        responsive : {
508          0: {
509            autoWidth: true
510          },
511          768: {
512            autoWidth: false,
513            items: 2
514          },
515          1100: {
516            items: 3
517          }
518        }
519      });
520    }
521  };
522
523  /**
524   * offre-emploi branding sliders
525   */
526  Drupal.behaviors.fhfoffresBrandingSlider = {
527    attach: function (context) {
528      if (context !== document) {
529        return;
530      }
531      $('.paragraph--type--branding .paragraph-content').each(function() {
532        $(this).addClass('owl-carousel mobile-slider').owlCarousel({
533          loop: false,
534          dots: false,
535          nav: true,
536          margin: 20,
537          navText : ["<span class='fhficon fhficon-angle-left'></span>","<span class='fhficon fhficon-angle-right'></span>"],
538          responsive : {
539            0: {
540              autoWidth: true
541            },
542            768: {
543              autoWidth: false,
544              items: 2
545            },
546            1100: {
547              items: 4
548            }
549          }
550        });
551      });
552
553    }
554  };
555
556  /**
557   * agenda carousel
558   */
559  Drupal.behaviors.fhfAgendaCarousel = {
560    attach: function (context) {
561      if (context !== document) {
562        return;
563      }
564      $('.view-agenda-carrousel .view-content').addClass('owl-carousel mobile-slider').owlCarousel({
565        loop: false,
566        dots: false,
567        nav: true,
568        margin: 20,
569        navText : ["<span class='fhficon fhficon-angle-left'></span>","<span class='fhficon fhficon-angle-right'></span>"],
570        responsive : {
571          0: {
572            autoWidth: true
573          },
574          768: {
575            autoWidth: false,
576            items: 3
577          },
578          1200: {
579            items: 5
580          }
581        }
582      });
583    }
584  };
585
586  /**
587   * Filter-list buttons
588   */
589  Drupal.behaviors.fhfFilterListButton = {
590    attach: function (context) {
591      if (context !== document) {
592        return;
593      }
594      // cherck if the url parameter 'display_style' is present. if it is, we apply the corresponding style
595      const queryString = window.location.search;
596      const urlParams = new URLSearchParams(queryString);
597      if(urlParams.has('display_style')) {
598        let listButton = $('.list-filter--tools button.btn-filter-list');
599        $(listButton).addClass('active')
600          .siblings()
601          .removeClass('active');
602        $(listButton).parents().find('.views-row').css('display', 'block');
603        $(listButton).parents('.view').attr('data-mode', 'list');
604      }
605      $('.view .list-filter--tools button', context).each(function () {
606        $(this).click(function () {
607          var target = $(this).parents().find('.views-row');
608          var map = $(this).parents().find('.view-display-id-map');
609
610          if (!$(this).hasClass('active')) {
611            $(this).addClass('active')
612              .siblings()
613              .removeClass('active');
614
615            if ($(this).hasClass('btn-filter-list')) {
616              target.css('display', 'block');
617              map.removeClass('show');
618              $('.pager').show();
619              $(this).parents('.view').attr('data-mode', 'list');
620              // add a parameter in pager items url, to keep the dislay after clicking on the button.
621              if(!urlParams.has('display_style')) {
622                /*
623                document.querySelectorAll('nav.pager .pager__item a').forEach(function (link) {
624                  link.href = link.href + "&display_style=list";
625                });
626
627                 */
628              }
629            } else if ($(this).hasClass('btn-filter-map')) {
630              target.hide();
631              map.addClass('show');
632              $('.pager').hide();
633              $(this).parents('.view').attr('data-mode', 'map');
634              // hotest fix
635              drupalSettings.leaflet[Object.keys(drupalSettings.leaflet)[0]].lMap.invalidateSize(false);
636              var bounds = drupalSettings.leaflet[Object.keys(drupalSettings.leaflet)[0]].features;
637              drupalSettings.leaflet[Object.keys(drupalSettings.leaflet)[0]].lMap.fitBounds(bounds);
638              window.dispatchEvent(new Event('resize'));
639            } else {
640              target.css('display', 'grid');
641              map.removeClass('show');
642              $('.pager').show();
643              $(this).parents('.view').attr('data-mode', 'grid');
644              // remove url parameter 'display_style' from pagination links
645              if(urlParams.has('display_style')) {
646                /*
647                document.querySelectorAll('nav.pager .pager__item a').forEach(function(link){
648                  let href = link.href;
649                  if (href.indexOf('&display_style=list') !== -1) {
650                    let replace = href.replace('&display_style=list');
651                    link.href = replace;
652                  }
653                });
654                */
655              }
656            }
657          }
658        });
659      });
660
661
662      $('.grid-container .list-filter--tools button', context).each(function () {
663        $(this).click(function () {
664          var target = $(this).parents().find('.views-row');
665
666          if (!$(this).hasClass('active')) {
667            $(this).addClass('active')
668              .siblings()
669              .removeClass('active');
670
671            if ($(this).hasClass('btn-filter-list')) {
672              target.css('display', 'block');
673              $('[data-display="content"]').removeClass('visually-hidden');
674              $('[data-display="map"]').addClass('visually-hidden');
675            } else if ($(this).hasClass('btn-filter-map')) {
676              $('[data-display="content"]').addClass('visually-hidden');
677              $('[data-display="map"]').removeClass('visually-hidden');
678              // hotest fix
679              drupalSettings.leaflet[Object.keys(drupalSettings.leaflet)[0]].lMap.invalidateSize(false);
680              var bounds = drupalSettings.leaflet[Object.keys(drupalSettings.leaflet)[0]].features;
681              drupalSettings.leaflet[Object.keys(drupalSettings.leaflet)[0]].lMap.fitBounds(bounds);
682              window.dispatchEvent(new Event('resize'));
683            } else {
684              target.css('display', 'grid');
685              $('[data-display="content"]').removeClass('visually-hidden');
686              $('[data-display="map"]').addClass('visually-hidden');
687            }
688          }
689        });
690      });
691
692    }
693  };
694
695  /**
696   * Account menu
697   */
698  Drupal.behaviors.fhfAccountMenu = {
699    attach: function (context) {
700      if (context !== document) {
701        return;
702      }
703      // Adding gradient background under user menu
704      var bannerBg = $('.js-top-bg', context);
705      var userMenu = $('#block-account-menu', context);
706
707      function setBg() {
708        if (userMenu.length) {
709          var height = userMenu.innerHeight();
710          bannerBg.height(height);
711        }
712      }
713
714      setBg();
715
716      $(window).resize(function() {
717        setBg();
718      });
719    }
720  };
721
722  /**
723   * modal alert
724   */
725  Drupal.behaviors.fhfModalAlert = {
726    attach: function (context) {
727      if (context !== document) {
728        return;
729      }
730      $('.alert.modal', context).each(function () {
731        $(this).on('click', function(e) {
732          if (e.target !== this)
733            return;
734
735          $(this).find('.btn-close').click();
736        });
737      });
738    }
739  };
740
741  /**
742   * Search page filters
743   */
744  Drupal.behaviors.fhfSearchFilters = {
745    attach: function (context) {
746      if (context !== document) {
747        return;
748      }
749      var searchField = $('.path-recherche .form--inline .js-form-item-created-year', context);
750      if (searchField.length) {
751        searchField.each(function() {
752          $(this).add($(this).next('.js-form-item-sort-bef-combine', context)).wrapAll('<div class="filter-group"></div>');
753        });
754      }
755    }
756  };
757
758  //Behavior for modals
759  Drupal.behaviors.ModalDialogClose = {
760    attach: function (context) {
761      if (context !== document) {
762        return;
763      }
764      /*
765      $(document, context).once('modalClose').on('click', '.ui-widget-overlay', function () {
766        $('.ui-dialog-titlebar-close').trigger('click');
767      });
768       */
769    }
770  };
771
772  Drupal.behaviors.fhfExternalLinkBlank = {
773    attach: function (context) {
774
775      document.addEventListener("DOMContentLoaded", function() {
776        const allowedDomains = ['fhf.fr', 'pockost.dev', 'localhost'];
777        const links = document.querySelectorAll('a[href]');
778
779        links.forEach(link => {
780          const linkHref = link.getAttribute('href');
781          const linkDomain = new URL(linkHref, window.location.origin).hostname;
782
783          // Vérifie si le domaine est autorisé ou si c’est un lien interne (commence par /)
784          const isAllowed = allowedDomains.some(domain => linkDomain.endsWith(domain));
785
786          if (!(isAllowed || linkHref.startsWith('/'))) {
787            link.setAttribute('target', '_blank');
788          }
789        });
790      });
791    }
792  };
793
794  Drupal.behaviors.fhfPrefixBtn = {
795    attach: function (context) {
796      const root = (context && context.querySelectorAll) ? context : document;
797      const elements = root.querySelectorAll(`.btn:not(.btn-search)`);
798
799      elements.forEach((el) => {
800        el.classList.add(`fhf-btn`);
801        el.classList.remove('btn');
802      });
803
804    }
805  };
806
807  Drupal.behaviors.fhfCarteGhtResize = {
808    attach: function (context) {
809      if (context !== document) {
810        return;
811      }
812      window.addEventListener("message", (e) => {
813        const iframe = Array.from(document.getElementsByTagName("iframe")).find(f => f.src.startsWith("https://carteght"));
814        if (e.data?.type === "carteght-resize" && iframe) {
815          iframe.style.height = e.data.height + "px";
816        }
817      });
818    }
819  };
820
821})(jQuery, Drupal, window, window.document);

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.