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(/</gm, '<') 940 res = res.replace(/>/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.