PageSourceSearch

https://www.semainesansecran.be/tools/bazar/libs/bazar.js?v=4.4.5

js semainesansecran.be collected 2026-10-04 18:45:56 UTC 32,711 bytes, 959 lines download raw bytes

1/**
2 *
3 * javascript for bazar
4 *
5 * */
6
7$(document).ready(() => {
8  // accordeon pour bazarliste
9  $('.titre_accordeon').on('click', function() {
10    if ($(this).hasClass('current')) {
11      $(this).removeClass('current')
12      $(this).next('div.pane').hide()
13    } else {
14      $(this).addClass('current')
15      $(this).next('div.pane').show()
16    }
17  })
18
19  // antispam javascript
20  $('input[name=antispam]').val('1')
21
22  // carto google
23  const divcarto = document.getElementById('map')
24  if (divcarto) {
25    initialize()
26  }
27
28  // clic sur le lien d'une fiche, l'ouvre sur la carto
29  $('#markers a').on('click', function() {
30    const i = $(this).attr('rel')
31
32    // this next line closes all open infowindows before opening the selected one
33    for (x = 0; x < arrInfoWindows.length; x++) {
34      arrInfoWindows[x].close()
35    }
36
37    arrInfoWindows[i].open(map, arrMarkers[i])
38    $('ul.css-tabs li').remove()
39    $('fieldset.tab').each(function(i) {
40      $(this)
41        .parent('div.BAZ_cadre_fiche')
42        .prev('ul.css-tabs')
43        .append(`<li class='liste${i}'><a href="#">${
44          $(this).find('legend:first').hide().html()}</a></li>`)
45    })
46
47    $('ul.css-tabs').tabs('fieldset.tab', { onClick() {} })
48  })
49
50  // initialise les tooltips pour l'aide et pour les cartes leaflet
51  $('img.tooltip_aide[title], .bazar-marker').each(function() {
52    $(this).tooltip({
53      animation: true,
54      delay: 0,
55      position: 'top'
56    })
57  })
58
59  // on enleve la fonction doubleclic dans le cas d'une page contenant bazar
60  $('#formulaire, #map, #calendar, .accordion').bind('dblclick', (e) => false)
61
62  function emptyChildren(element) {
63    if (typeof ConditionsChecking === 'undefined') {
64      // backward compatibility old system (not clean) TODO remove it when ConditionsChecking is sure to be installed (even in local cahe)
65      $(element).find(':input').val('').removeProp('checked')
66    } else {
67      ConditionsChecking.emptyChildren(element)
68    }
69  }
70
71  // TODO : when conditionschecking is the only system (ex: for ectoplasme) remove the followings line to manage
72  // conditions by the old way
73
74  // permet de gerer des affichages conditionnels, en fonction de balises div
75  function handleConditionnalListChoice() {
76    const id = $(this).attr('id')
77    $(`div[id^='${id}'], div[id^='${id.replace('liste', '')}']`)
78      .not(`div[id='${id}_${$(this).val()}'], div[id='${id.replace('liste', '')}_${$(this).val()}']`).hide()
79      .each(function() {
80        emptyChildren(this)
81      })
82    $(`div[id='${id}_${$(this).val()}'], div[id='${id.replace('liste', '')}_${$(this).val()}']`).show()
83  }
84  function handleConditionnalRadioChoice() {
85    const id = $(this).attr('id')
86    const shortId = id.substr(0, id.length - $(this).val().toString().length - 1)
87    $(`div[id^='${shortId}']`)
88      .not(`div[id='${id}']`).hide()
89      .each(function() {
90        emptyChildren(this)
91      })
92    $(`div[id='${id}']`).show()
93  }
94  function handleConditionnalCheckboxChoice() {
95    const id = $(this).attr('id')
96    const re = /^([a-zA-Z0-9-_]+)\[([a-zA-Z0-9-_]+)\]$/
97    let m
98
99    if ((m = re.exec(id)) !== null) {
100      if (m.index === re.lastIndex) {
101        re.lastIndex++
102      }
103    }
104    if (m) {
105      if ($(this).prop('checked') == true) {
106        $(`div[id='${m[1]}_${m[2]}']:not(.conditional_inversed_checkbox)`).show()
107        $(`div[id='${m[1]}_${m[2]}'].conditional_inversed_checkbox`).hide()
108          .each(function() {
109            emptyChildren(this)
110          })
111      } else {
112        $(`div[id='${m[1]}_${m[2]}']:not(.conditional_inversed_checkbox)`).hide()
113          .each(function() {
114            emptyChildren(this)
115          })
116        $(`div[id='${m[1]}_${m[2]}'].conditional_inversed_checkbox`).show()
117      }
118    }
119  }
120
121  $('select[id^=\'liste\']').each(handleConditionnalListChoice).change(handleConditionnalListChoice)
122  $('input.element_radio').each(handleConditionnalRadioChoice).change(handleConditionnalRadioChoice)
123  $('.element_checkbox[id^=\'checkboxListe\']').each(handleConditionnalCheckboxChoice).change(handleConditionnalCheckboxChoice)
124
125  // choix de l'heure pour une date
126  $('.select-allday').change(function() {
127    if ($(this).val() === '0') {
128      $(this).parent().next('.select-time').removeClass('hide')
129    } else if ($(this).val() === '1') {
130      $(this).parent().next('.select-time').addClass('hide')
131    }
132  })
133
134  //= ===========longueur maximale d'un champs textarea
135  const $textareas = $('textarea[maxlength].form-control')
136
137  // si les textarea contiennent déja quelque chose, on calcule les caractères restants
138  $textareas.each(function() {
139    const $this = $(this)
140    const max = $this.attr('maxlength')
141    const { length } = $this.val()
142    if (length > max) {
143      $this.val($this.val().substr(0, max))
144    }
145
146    $this.parents('.control-group').find('.charsRemaining').html((max - length))
147  })
148
149  // on empeche d'aller au dela de la limite du nombre de caracteres
150  $textareas.on('keyup', function() {
151    const $this = $(this)
152    const max = $this.attr('maxlength')
153    const { length } = $this.val()
154    if (length > max) {
155      $this.val($this.val().substr(0, max))
156    }
157
158    $this.parents('.control-group').find('.charsRemaining').html((max - length))
159  })
160
161  // éviter la validation du formulaire en pressant la touche Entrée
162  document.querySelectorAll('form#formulaire .control-group.form-group input.form-control[type=text]').forEach((item)=>{
163    item.addEventListener('keydown',(event)=>{
164      if (event.key === "Enter"){
165        event.preventDefault();
166        event.stopPropagation();
167        return true;
168      }
169    },
170    true)
171  })
172
173  //= =========== bidouille pour que les widgets en flash restent ===========
174  //= =========== en dessous des éléments en survol ===========
175  $('object').append('<param value="opaque" name="wmode">')
176  $('embed').attr('wmode', 'opaque')
177
178  //= ===========validation formulaire============================
179  //= ===========gestion des dates================================
180
181  // validation formulaire de saisie
182  const requirementHelper = {
183    requiredInputs: [],
184    textInputsWithPattern: [],
185    error: -1, // error contain the index of the first error (-1 = no error)
186    errorMessage: '',
187    errorPattern: -1,
188    errorMessagePattern: '',
189    filterVisibleInputs(key = 'requiredInputs') {
190      this[key] = (this[key]).filter(function() {
191        let inputVisible = $(this).filter(':visible')
192        if ((
193          $(this).prop('tagName') == 'TEXTAREA' && ($(this).hasClass('wiki-textarea') || $(this).hasClass('summernote'))
194        ) || $(this).siblings('.bootstrap-tagsinput').length > 0) {
195          inputVisible = $(this).parent().filter(':visible')
196        }
197        if (typeof inputVisible !== 'undefined' && inputVisible.length > 0) {
198          return true
199        }
200        const notVisibleParents = $(this).parentsUntil(':visible')
201        if (typeof notVisibleParents === 'undefined' || notVisibleParents.length == 0) {
202          return false
203        }
204        // check if visible in a tab
205        if ($(this).parentsUntil(':visible')
206          .filter(function() {
207            return $(this).css('display') == 'none'
208                && $(this).attr('role') != 'tabpanel'
209          }).length == 0) {
210          return true
211        }
212        return false
213      })
214    },
215    getInputType(input) {
216      if ($(input).hasClass('bazar-date')) {
217        return 'date'
218      }
219      if ($(input).hasClass('chk_required')) {
220        return 'checkbox'
221      }
222      if ($(input).hasClass('geocode-input')) {
223        return 'geocode'
224      }
225      if ($(input).hasClass('radio_required')) {
226        return 'radio'
227      }
228      if ($(input).siblings('.bootstrap-tagsinput').length > 0) {
229        return 'tags'
230      }
231      if ($(input).attr('type') == 'email') {
232        return 'email'
233      }
234      if ($(input).attr('type') == 'url') {
235        return 'url'
236      }
237      if ($(input).attr('type') == 'range') {
238        return 'range'
239      }
240      if ($(input).prop('tagName') == 'SELECT') {
241        return 'select'
242      }
243      if ($(input).prop('tagName') == 'TEXTAREA') {
244        if ($(input).hasClass('wiki-textarea')) {
245          return 'wikitextarea'
246        }
247        if ($(input).hasClass('summernote')) {
248          return 'summernote'
249        }
250        return 'textarea'
251      }
252      return 'default'
253    },
254    updateError(index) {
255      if (this.error == -1) {
256        this.error = index
257      }
258    },
259    updateErrorMessage(message) {
260      if (this.error == -1) {
261        this.errorMessage = message
262      }
263    },
264    dateChecking(input) {
265      if ($(input).val() === '') {
266        this.updateErrorMessage(_t('BAZ_FORM_REQUIRED_FIELD'))
267        return false
268      }
269      return true
270    },
271    rangeChecking(input) {
272      if ($(input).val() === $(input).data('default')) {
273        this.updateErrorMessage(_t('BAZ_FORM_REQUIRED_FIELD'))
274        return false
275      }
276      return true
277    },
278    emailChecking(input) {
279      const reg = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/ // regex that works for 99,99%, following RFC 5322
280      if ($(input).prop('required') && !this.defaultChecking(input)) {
281        return false
282      } if ($(input).val() != '' && reg.test($(input).val()) === false) {
283        this.updateErrorMessage(_t('BAZ_FORM_INVALID_EMAIL'))
284        return false
285      }
286      return true
287    },
288    urlChecking(input) {
289      const reg = /(ftp|http|https):\/\/(\w+:{0,1}\w*@)?(\S+)(:[0-9]+)?(\/|\/([\w#!:.?+=&%@!\-\/]))?/
290      if ($(input).prop('required') && !this.defaultChecking(input)) {
291        return false
292      } if ($(input).val() != '' && reg.test($(input).val()) === false) {
293        this.updateErrorMessage(_t('BAZ_FORM_INVALID_URL'))
294        return false
295      }
296      return true
297    },
298    selectChecking(input) {
299      return this.defaultChecking(input)
300    },
301    textareaChecking(input) {
302      return this.defaultChecking(input)
303    },
304    wikitextareaChecking(input) {
305      const value = $(input).data('aceditor').getValue()
306      if (value.length === 0 || value === '') {
307        this.updateErrorMessage(_t('BAZ_FORM_REQUIRED_FIELD'))
308        $(input).parent().addClass('invalid')
309        return false
310      }
311      $(input).parent().removeClass('invalid')
312      return true
313    },
314    summernoteChecking(input) {
315      if ($(input).summernote('isEmpty')) {
316        $(input).closest('.form-control.textarea.summernote').addClass('invalid')
317        this.updateErrorMessage(_t('BAZ_FORM_REQUIRED_FIELD'))
318        return false
319      }
320      $(input).closest('.form-control.textarea.summernote').removeClass('invalid')
321      return true
322    },
323    checkboxChecking(input) {
324      const nbelems = $(input).find('input:checked')
325      const parentToInvalid = $(input).closest('.form-group.input-checkbox')
326      if (nbelems.length === 0) {
327        this.updateErrorMessage(_t('BAZ_FORM_EMPTY_CHECKBOX'))
328        $(parentToInvalid).addClass('invalid')
329        return false
330      }
331      $(parentToInvalid).removeClass('invalid')
332      return true
333    },
334    radioChecking(input) {
335      const nbelems = $(input).find('input:checked')
336      const parentToInvalid = $(input).closest('.form-group.input-radio')
337      if (nbelems.length === 0) {
338        this.updateErrorMessage(_t('BAZ_FORM_EMPTY_RADIO'))
339        $(parentToInvalid).addClass('invalid')
340        return false
341      }
342      $(parentToInvalid).removeClass('invalid')
343      return true
344    },
345    tagsChecking(input) {
346      const bootstrapBaseDiv = $(input).siblings('.bootstrap-tagsinput')
347      const nbelems = $(bootstrapBaseDiv).find('.tag')
348      if (nbelems.length === 0) {
349        this.updateErrorMessage(_t('BAZ_FORM_EMPTY_AUTOCOMPLETE'))
350        $(bootstrapBaseDiv).addClass('invalid')
351        return false
352      }
353      $(bootstrapBaseDiv).removeClass('invalid')
354      return true
355    },
356    geocodeChecking(input) {
357      if (!$(input).find('#bf_latitude').val()) {
358        this.updateErrorMessage(_t('BAZ_FORM_EMPTY_GEOLOC'))
359        return false
360      }
361      return true
362    },
363    defaultChecking(input) {
364      if ($(input).val().length === 0 || $(input).val() === '') {
365        this.updateErrorMessage(_t('BAZ_FORM_REQUIRED_FIELD'))
366        return false
367      }
368      return true
369    },
370    checkInput(input, saveError, index) {
371      const inputType = this.getInputType(input)
372      if (typeof this[`${inputType}Checking`] !== 'function') {
373        $(input).addClass('invalid')
374        this.updateErrorMessage(`Not possible to check field : unknown function requirementHelper.${inputType}Checking() !`)
375        if (saveError) {
376          this.updateError(index)
377        }
378      } else if (!(this[`${inputType}Checking`](input))) {
379        $(input).addClass('invalid')
380        if (saveError) {
381          this.updateError(index)
382        }
383      } else {
384        $(input).removeClass('invalid')
385      }
386    },
387    checkPattern(input,index){
388      if ($(input)[0]){
389        const val = $(input).val()
390        const element = $(input)[0]
391        if (val.length > 0){
392          if (!element.checkValidity()){
393            if (this.errorPattern == -1) {
394              this.errorMessagePattern = _t('BAZ_FORM_INVALID_TEXT')
395              this.errorPattern= index
396            }
397          }
398        }
399      }
400    },
401    checkInputs() {
402      for (let index = 0; index < this.requiredInputs.length; index++) {
403        const input = this.requiredInputs[index]
404        this.checkInput(input, true, index)
405      }
406      for (let index = 0; index < this.textInputsWithPattern.length; index++) {
407        const input = this.textInputsWithPattern[index]
408        this.checkPattern(input, index)
409      }
410    },
411    displayErrorMessage() {
412      alert(this.errorMessage)
413    },
414    scrollToFirstinputInError(type = 'error') {
415      const error = this[type] ?? -1
416      if (error > -1) {
417        // TODO afficher l'onglet en question
418        // on remonte en haut du formulaire
419        let input = this.requiredInputs[error]
420        if ($(input).filter(':visible').length == 0) {
421          // panel ?
422          const panel = $(input).parentsUntil(':visible').last()
423          if ($(panel).attr('role') == 'tabpanel') {
424            $(`a[href="#${$(panel).attr('id')}"][role=tab]`).first().click()
425          }
426          if ($(input).filter(':visible').length == 0) {
427            input = $(input).closest(':visible')
428          }
429        }
430        $('html, body').animate({ scrollTop: $(input).offset().top - 80 }, 500)
431      }
432    },
433    initTextInputsWithPattern(form) {
434      this.textInputsWithPattern = $(form).find('input[type=text][pattern]')
435      this.errorPattern = -1
436    },
437    initRequiredInputs(form) {
438      this.requiredInputs = $(form).find(
439        'input[required],'
440        + 'select[required],'
441        + 'textarea[required],'
442        + ':not(.prev-holder) input[type=email],'
443        + ':not(.prev-holder) input[type=url],'
444        + '.chk_required,'
445        + '.radio_required,'
446        + '.geocode-input.required'
447      )
448      this.error = -1
449    },
450    run(form) {
451      this.initRequiredInputs(form)
452      this.initTextInputsWithPattern(form)
453      this.filterVisibleInputs('requiredInputs')
454      this.filterVisibleInputs('textInputsWithPattern')
455      this.checkInputs()
456      if (this.error > -1) {
457        this.displayErrorMessage()
458        this.scrollToFirstinputInError('error')
459        return false
460      }
461      if (this.errorPattern > -1) {
462        alert(this.errorMessagePattern)
463        this.scrollToFirstinputInError('errorPattern')
464        return false
465      }
466      return true
467    },
468    runWhenUpdated(target, reqChecking) {
469      reqChecking.checkInput(target, false, 0)
470    },
471    inputInitlistener(input) {
472      const reqChecking = this
473      $(input).keypress((event) => {
474        reqChecking.runWhenUpdated(event.target, reqChecking)
475      })
476      $(input).change((event) => {
477        reqChecking.runWhenUpdated(event.target, reqChecking)
478      })
479    },
480    summernoteInitlistener(input) {
481      const reqChecking = this
482      $(input).on('summernote.change', (event) => {
483        reqChecking.runWhenUpdated(event.target, reqChecking)
484      })
485    },
486    wikitextareaInitlistener(input) {
487      const reqChecking = this
488      const aceditor = $(input).data('aceditor')
489      aceditor.on('change', (event) => {
490        reqChecking.runWhenUpdated(input, reqChecking)
491      })
492    },
493    checkboxInitlistener(input) {
494      const reqChecking = this
495      const checkboxes = $(input).find('input[type=checkbox]')
496      $(checkboxes).change((event) => {
497        reqChecking.runWhenUpdated($(event.target).closest('.chk_required'), reqChecking)
498      })
499    },
500    radioInitlistener(input) {
501      const reqChecking = this
502      const radioButtons = $(input).find('input[type=radio]')
503      $(radioButtons).change((event) => {
504        reqChecking.runWhenUpdated($(event.target).closest('.radio_required'), reqChecking)
505      })
506    },
507    initListeners() {
508      this.initRequiredInputs($('#formulaire'))
509      for (let index = 0; index < this.requiredInputs.length; index++) {
510        const input = this.requiredInputs[index]
511        const inputType = this.getInputType(input)
512        if (['default', 'select', 'textarea', 'tags'].indexOf(inputType) > -1) {
513          this.inputInitlistener(input)
514        } else if (['summernote', 'wikitextarea', 'checkbox', 'radio'].indexOf(inputType) > -1) {
515          this[`${inputType}Initlistener`](input)
516        }
517      }
518    }
519  }
520
521  requirementHelper.initListeners()
522
523  $('#formulaire').submit(function(e) {
524    $(this).addClass('submitted')
525
526    try {
527      if (requirementHelper.run(this)) {
528        // formulaire validé, on soumet le formulaire
529        // mais juste avant on change le comportement du bouton pour éviter les validations multiples
530        $(this).find('.form-actions button[type=submit]').each(function() {
531          $(this).attr('disabled', true)
532          $(this).addClass('submit-disabled')
533          $(this).attr('title', _t('BAZ_SAVING'))
534          const button = $(this)
535          setTimeout(() => {
536            // on réactive le bouton au bout de 10s juste pour permettre de forcer une nouvelle validation si jamais ça a planté
537            $(button).removeAttr('disabled')
538          }, 10000)
539        })
540        return true
541      }
542    } catch (error) {
543      console.warn(error.message)
544    }
545    e.preventDefault()
546    return false
547  })
548
549  // bidouille PEAR form
550  $('#formulaire').removeAttr('onsubmit')
551
552  // selecteur de dates
553  const $dateinputs = $('.bazar-date')
554
555  // test pour verifier si le browser gere l'affichage des dates
556  // var input = document.createElement('input');
557  // input.setAttribute('type','date');
558  // var notADateValue = 'not-a-date';
559  // input.setAttribute('value', notADateValue);
560
561  // if ($dateinputs.length > 0 && (input.value == notADateValue)) {
562  if ($dateinputs.length > 0) {
563    $.fn.datepicker.dates.fr = {
564      days: ['SUNDAY', 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY']
565        .map((day) => _t(day)),
566      daysShort: ['SUNDAY', 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY']
567        .map((day) => _t(`BAZ_DATESHORT_${day}`)),
568      daysMin: ['SUNDAY', 'MONDAY', 'TUESDAY', 'WEDNESDAY', 'THURSDAY', 'FRIDAY', 'SATURDAY', 'SUNDAY']
569        .map((day) => _t(`BAZ_DATEMIN_${day}`)),
570      months: ['JANUARY', 'FEBRUARY', 'MARCH', 'APRIL', 'MAY', 'JUNE', 'JULY', 'AUGUST', 'SEPTEMBER', 'OCTOBER', 'NOVEMBER', 'DECEMBER']
571        .map((month) => _t(month)),
572      monthsShort: ['JANUARY', 'FEBRUARY', 'MARCH', 'APRIL', 'MAY', 'JUNE', 'JULY', 'AUGUST', 'SEPTEMBER', 'OCTOBER', 'NOVEMBER', 'DECEMBER']
573        .map((month) => _t(`BAZ_DATESHORT_${month}`))
574    }
575    $dateinputs.datepicker({
576      format: 'yyyy-mm-dd',
577      weekStart: 1,
578      autoclose: true,
579      language: 'fr'
580    }).attr('autocomplete', 'off')
581  }
582
583  // If start_date is greater than en_date, set end_date to start_date
584  $startDate = $('#formulaire #bf_date_debut_evenement')
585  $endDate = $('#formulaire #bf_date_fin_evenement')
586  if ($startDate && $endDate) {
587    $startDate.change(() => {
588      if (new Date($startDate.val()) > new Date($endDate.val())) $endDate.val($startDate.val())
589    })
590  }
591
592  // Onglets
593  // hack pour les fiches avec tabulations : on change les id pour qu'ils soient uniques
594  $('.bazar-entry').each(function(i) {
595    $(this).find('[data-toggle="tab"]').each(function() {
596      $(this).attr('href', `${$(this).attr('href')}-${i}`)
597    })
598
599    $(this).find('.tab-pane').each(function() {
600      $(this).attr('id', `${$(this).attr('id')}-${i}`)
601    })
602  })
603
604  // cocher / decocher tous
605  const checkboxselectall = $('.selectall')
606  checkboxselectall.click(function(event) {
607    const $this = $(this)
608    let target = $this.parents('.controls').find('.yeswiki-checkbox')
609    if ($this.data('target')) {
610      target = $($this.data('target'))
611    }
612
613    if (this.checked) { // check select status
614      target.each(function() {
615        $(this).find(':checkbox').prop('checked', true)
616        $(this).prop('checked', true)
617      })
618    } else {
619      target.each(function() {
620        $(this).find(':checkbox').prop('checked', false)
621        $(this).prop('checked', false)
622      })
623    }
624  })
625
626  // facettes
627
628  // recuperer un parametre donné de l'url
629  function getURLParameter(name) {
630    return decodeURIComponent(
631      (new RegExp(`[?|&]${name}=` + '([^&;]+?)(&|#|;|$)').exec(location.search) || [, ''])[1]
632        .replace(/\+/g, '%20')
633    ) || null
634  }
635
636  // modifier un parametre de l'url pour les modifier dynamiquement
637  function changeURLParameter(name, value) {
638    if (getURLParameter(name) == null) {
639      var s = location.search
640      var urlquery = s.replace(`&${name}=`, '').replace(`?${name}=`, '')
641      if (value !== '') {
642        if (s !== '') {
643          urlquery += `&${name}=${value}`
644        } else {
645          urlquery += `?${name}=${value}`
646        }
647      }
648
649      history.pushState({ filter: true }, null, urlquery)
650
651      // pour les url dans une iframe
652      if (window.frameElement && window.frameElement.nodeName == 'IFRAME') {
653        var iframeurlquery = `${window.top.location.search
654          .replace(`&${name}=`, '')}&${name}=${value}`
655        window.top.history.pushState({ filter: true }, null, iframeurlquery)
656      }
657    } else {
658      var s = location.search
659      // console.log('s', s, s !== '', decodeURIComponent(s));
660      // console.log('value', value);
661      var urlquery
662      if (value !== '') {
663        if (s !== '') {
664          // console.log(s);
665          urlquery = decodeURIComponent(s).replace(
666            new RegExp(`&${name}=` + '([^&;]+?)(&|#|;|$)'),
667            `&${name}=${value}`
668          )
669          // console.log('location.search', s, urlquery);
670        } else {
671          urlquery = `?${name}=${value}`
672        } // console.log('location.search vide', s, urlquery);
673      } else {
674        // console.log(s);
675        urlquery = decodeURIComponent(s).replace(
676          new RegExp(`[?|&]${name}=` + '([^&;]+?)(&|#|;|$)'),
677          ''
678        )
679      }
680
681      history.pushState({ filter: true }, null, urlquery)
682
683      // pour les url dans une iframe
684      if (window.frameElement && window.frameElement.nodeName == 'IFRAME') {
685        var iframeurlquery = decodeURIComponent(window.top.location.search).replace(
686          new RegExp(`[?|&]${name}=` + '([^&;]+?)(&|#|;|$)'),
687          `&${name}=${value}`
688        )
689        window.top.history.pushState({ filter: true }, null, iframeurlquery)
690      }
691
692      return location.search
693    }
694  }
695
696  // activer les filtres des facettes
697  function updateFilters(e) {
698    const tabfilters = Array()
699    let i = 0
700    let newquery = ''
701    let select
702
703    // on filtre les resultat par boite de filtre pour faire l'intersection apres
704    e.data.$filterboxes.each(function() {
705      select = ''
706      let first = true
707      const filterschk = $(this).find('.filter-checkbox:checked')
708      $.each(filterschk, (index, checkbox) => {
709        // les valeurs sont mis en cache
710        const name = $(checkbox).attr('name')
711        const val = $(checkbox).attr('value')
712        const attr = `data-${name.toLowerCase()}`
713        if (first) {
714          // si ce n'est pas le premier appel, on ajoute un | pour separer les query
715          if (newquery !== '') {
716            newquery += '|'
717          }
718          newquery += `${name}=${val}`
719          first = false
720        } else {
721          newquery += `,${val}`
722          select += ','
723        }
724        // La requete de selection prend pour les champs non multiples :
725        // - exactement la valeur de l'attribut html
726        // Pour les champs multiples :
727        // - soit les attributs commencant par la valeur suivie d'une virgule
728        // - soit les attributs finissant par la valeur avec une virgule avant
729        // - soit les attributs contenant la valeur entouree de virgules
730        select += `[${attr}~="${val}"],[${attr}$=",${val}"],[${attr}^="${val},"],[${attr}*=",${val},"]`
731      })
732      const res = e.data.$entries.filter(select)
733
734      if (res.length > 0) {
735        tabfilters[i] = res
736        i += 1
737      }
738    })
739
740    // on applique les changements a l'url
741    changeURLParameter('facette', newquery)
742
743    // on ajuste les liens vers les formulaires d'export
744    $('.export-links a').each(
745      function() {
746        const link = $(this).attr('href')
747        const queryexists = new RegExp('&query=' + '([^&;]+?)(&|#|;|$)').exec(link) || null
748        if (queryexists == null) {
749          $(this).attr('href', link + ((newquery !== '') ? `&query=${newquery}` : ''))
750        } else {
751          const queryinit = $('#queryinit').val()
752          if (queryinit) { newquery = `${queryinit}|${newquery}` }
753          $(this).attr(
754            'href',
755            link.replace(new RegExp('&query=' + '([^&;]+?)(&|#|;|$)'), ((newquery !== '') ? `&query=${newquery}` : ''))
756          )
757        }
758      }
759    )
760
761    // au moins un filtre à actionner
762    let tabres = []
763    if (tabfilters.length > 0) {
764      // un premier résultat pour le tableau
765      tabres = tabfilters[0].toArray()
766
767      // pour chaque boite de filtre, on fait l'intersection avec la suivante
768      $.each(tabfilters, (index, tab) => {
769        tabres = tabres.filter((n) => tab.toArray().indexOf(n) != -1)
770      })
771      $('body').trigger('updatefilters', [tabres])
772      e.data.$entries.hide().filter(tabres).show()
773      e.data.$entries.parent('.bazar-marker').hide()
774      e.data.$entries.filter(tabres).parent('.bazar-marker').show()
775    } else {
776      // pas de filtres: on affiche tout les résultats
777      e.data.$entries.show()
778      e.data.$entries.parent('.bazar-marker').show()
779    }
780
781    // on compte les résultats visibles
782    const nbresults = e.data.$entries.filter(':visible').length
783    e.data.$nbresults.html(nbresults)
784    if (nbresults > 1) {
785      e.data.$resultlabel.hide()
786      e.data.$resultslabel.show()
787    } else {
788      e.data.$resultlabel.show()
789      e.data.$resultslabel.hide()
790    }
791
792    $('body').trigger('updatedfilters', (!tabres.length) ? [] : [tabres])
793  }
794
795  // process changes on visible entries according to filters
796  $('.facette-container:not(.dynamic)').each(function() {
797    const $container = $(this)
798    const $filters = $('.filter-checkbox', $container)
799    const data = {
800      $nbresults: $('.nb-results', $container),
801      $filterboxes: $('.filter-box', $container),
802      $entries: $('.bazar-entry', $container),
803      $resultlabel: $('.result-label', $container),
804      $resultslabel: $('.results-label', $container)
805    }
806    $filters.on('click', data, updateFilters)
807    jQuery(window).ready((e) => {
808      e.data = data
809      updateFilters(e)
810    })
811  })
812
813  // gestion de l'historique : on reapplique les filtres
814  window.onpopstate = function(e) {
815    if (e.state && e.state.filter) {
816      $('.facette-container').each(function() {
817        const $this = $(this)
818        $(this).find('input:checkbox').prop('checked', false)
819        const urlparamfacette = getURLParameter('facette')
820        const tabfacette = urlparamfacette.split('|')
821        for (let i = 0; i < tabfacette.length; i++) {
822          const tabfilter = tabfacette[i].split('=')
823          if (tabfilter[1] !== '') {
824            tabvalues = tabfilter[1].split(',')
825            for (let j = 0; j < tabvalues.length; j++) {
826              $(`#${tabfilter[0]}${tabvalues[j]}`).prop('checked', true)
827            }
828          }
829        }
830
831        const $container = $(this)
832        const $filters = $('.filter-checkbox', $container)
833        const data = {
834          $nbresults: $('.nb-results', $container),
835          $filterboxes: $('.filter-box', $container),
836          $entries: $('.bazar-entry', $container),
837          $resultlabel: $('.result-label', $container),
838          $resultslabel: $('.results-label', $container)
839        }
840        e.data = data
841        updateFilters(e)
842      })
843    }
844  }
845
846  // Tags
847  // bidouille pour les typeahead des champs tags
848  $('.bootstrap-tagsinput input').on('keypress', function() {
849    $(this).attr('size', $(this).val().length + 2)
850  })
851
852  $('.bootstrap-tagsinput').on('change', function() {
853    $(this).parent().find('.yeswiki-input-entries, .yeswiki-input-pagetag').each(function() {
854      $(this).tagsinput('input').val('')
855    })
856  })
857
858  $.extend($.fn.typeahead.Constructor.prototype, { val() {} })
859
860  // on envoie la valeur au submit
861  $('#formulaire').on('submit', function() {
862    $(this).find('.yeswiki-input-entries, .yeswiki-input-pagetag').each(function() {
863      $(this).tagsinput('add', $(this).tagsinput('input').val())
864    })
865  })
866
867  const bazarList = []
868  $('.facette-container:not(.dynamic) .filter-bazar').on('keyup', function(e) {
869    const target = $(this).data('target')
870    let searchstring = $(this).val()
871    if (searchstring) {
872      searchstring = searchstring.toLowerCase()
873    }
874    if (bazarList[target] === undefined) {
875      bazarList[target] = []
876      $(`#${target} .bazar-entry`).each(function() {
877        bazarList[target][$(this).data('id_fiche')] = $(this).find(':visible').text().toLowerCase()
878      })
879    }
880    $(`#${target} .bazar-entry`).hide()
881    $(`#${target} .bazar-entry`).filter(function(i) {
882      return bazarList[target][$(this).data('id_fiche')].indexOf(searchstring) > -1
883    }).show()
884    const nbresults = $(`#${target} .bazar-entry:visible`).length
885    $(this).parents('.facette-container').find('.nb-results').html(nbresults)
886    if (nbresults > 1) {
887      $(this).parents('.facette-container').find('.result-label').hide()
888      $(this).parents('.facette-container').find('.results-label').show()
889    } else {
890      $(this).parents('.facette-container').find('.result-label').show()
891      $(this).parents('.facette-container').find('.results-label').hide()
892    }
893  })
894
895  // gestion du bouton de réinitialisation des filtres
896  $('.facette-container:not(.dynamic) .filters .reset-filters').on('click', () => {
897    $('.facette-container:not(.dynamic) .filters input.filter-checkbox:checked').click()
898  })
899})
900
901function exportTableToCSV(filename, selector = 'table tr') {
902  const csv = []
903  const rows = document.querySelectorAll(selector)
904
905  for (let i = 0; i < rows.length; i++) {
906    const row = []; const
907      cols = rows[i].querySelectorAll('td, th')
908
909    for (let j = 0; j < cols.length; j++) row.push(cols[j].innerText)
910
911    csv.push(row.join(','))
912  }
913
914  // Download CSV file
915  downloadCSV(csv.join('\n'), filename)
916}
917
918function downloadCSV(csv, filename) {
919  let csvFile
920  let downloadLink
921
922  // CSV file
923  csvFile = new Blob([csv], { type: 'text/csv' })
924  // Download link
925  downloadLink = document.createElement('a')
926  // File name
927  downloadLink.download = filename
928  // Create a link to the file
929  downloadLink.href = window.URL.createObjectURL(csvFile)
930  // Hide download link
931  downloadLink.style.display = 'none'
932  // Add the link to DOM
933  document.body.appendChild(downloadLink)
934  // Click download link
935  downloadLink.click()
936}
937
938function removeCSVCrochet(str) {
939  let res = str.replace(/&lt;/gm, '<')
940  res = res.replace(/&gt;/gm, '>')
941  return res
942}
943
944// range input
945$(document).ready(() => {
946  const rangeInputs = document.querySelectorAll('.range-wrap input[type="range"]')
947  function handleInputChange(e) {
948    const { target } = e
949    const { min } = target
950    const { max } = target
951    const val = target.value
952    target.style.backgroundSize = `${(val - min) * 100 / (max - min)}% 100%`
953    $(target).siblings('output').val(val)
954  }
955
956  rangeInputs.forEach((input) => {
957    input.addEventListener('input', handleInputChange)
958  })
959})

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.