1/* 2 * Accessibilité des flèches « mois précédent / mois suivant » du datepicker 3 * jQuery UI 1.12.1 utilisé par les agendas (RGAA 7.1, 7.3, 10.7). 4 * 5 * jQuery UI génère des <a> sans href : non atteignables au clavier, sans rôle, 6 * intitulés « Précédent » / « Suivant » peu explicites, et le focus est perdu 7 * à chaque redessin du calendrier (changement de mois, rafraîchissement ajax). 8 */ 9(function ($) { 10 if (!$ || !$.datepicker || $.datepicker._webseeAccessible) 11 return; 12 13 $.datepicker._webseeAccessible = true; 14 15 var textes = { 16 fr: { prev: 'Mois précédent', next: 'Mois suivant' }, 17 en: { prev: 'Previous month', next: 'Next month' } 18 }; 19 20 var langue = (document.documentElement.lang || 'fr').substring(0, 2).toLowerCase(); 21 var t = textes[langue] || textes.fr; 22 23 var $annonce = null; 24 25 // Zone de statut persistante : annonce le mois affiché aux lecteurs d'écran 26 function annoncer(texte) { 27 if ($annonce === null) 28 $annonce = $('<div class="ui-helper-hidden-accessible" role="status" aria-live="polite"></div>').appendTo('body'); 29 30 $annonce.text(texte); 31 } 32 33 function libelleMois(inst, decalage) { 34 var noms = $.datepicker._get(inst, 'monthNames'); 35 var date = new Date(inst.drawYear, inst.drawMonth + decalage, 1); 36 37 return noms[date.getMonth()] + ' ' + date.getFullYear(); 38 } 39 40 function rendreAccessible(inst) { 41 var pas = $.datepicker._get(inst, 'stepMonths'); 42 43 inst.dpDiv.find('.ui-datepicker-prev, .ui-datepicker-next').each(function () { 44 var $fleche = $(this); 45 var sens = $fleche.hasClass('ui-datepicker-prev') ? 'prev' : 'next'; 46 var libelle = t[sens] + ' : ' + libelleMois(inst, sens === 'prev' ? -pas : pas); 47 48 $fleche.attr({ 'role': 'button', 'title': libelle, 'aria-label': libelle }); 49 50 if ($fleche.hasClass('ui-state-disabled')) 51 $fleche.attr('aria-disabled', 'true'); 52 else 53 $fleche.attr('tabindex', '0'); 54 }); 55 } 56 57 var updateOriginal = $.datepicker._updateDatepicker; 58 59 $.datepicker._updateDatepicker = function (inst) { 60 var actif = document.activeElement; 61 var sensFocus = null; 62 63 if (actif && inst.dpDiv.length && $.contains(inst.dpDiv[0], actif)) { 64 if ($(actif).hasClass('ui-datepicker-prev')) 65 sensFocus = 'prev'; 66 else if ($(actif).hasClass('ui-datepicker-next')) 67 sensFocus = 'next'; 68 } 69 70 var moisAvant = inst.webseeMois; 71 72 updateOriginal.apply(this, arguments); 73 rendreAccessible(inst); 74 75 inst.webseeMois = inst.drawYear * 12 + inst.drawMonth; 76 77 // Le HTML est entièrement régénéré : on redonne le focus à la flèche équivalente 78 if (sensFocus !== null) { 79 var $cible = inst.dpDiv.find('.ui-datepicker-' + sensFocus + '[tabindex]'); 80 81 if (!$cible.length) 82 $cible = inst.dpDiv.find('.ui-datepicker-prev[tabindex], .ui-datepicker-next[tabindex]'); 83 84 $cible.first().trigger('focus'); 85 } 86 87 if (moisAvant !== undefined && moisAvant !== inst.webseeMois) 88 annoncer(inst.dpDiv.find('.ui-datepicker-title').first().text()); 89 }; 90 91 // Activation au clavier (Entrée / Espace) comme un bouton natif 92 $(document).on('keydown', '.ui-datepicker-prev[role=button], .ui-datepicker-next[role=button]', function (e) { 93 if (e.which !== 13 && e.which !== 32) 94 return; 95 96 e.preventDefault(); 97 98 if (!$(this).hasClass('ui-state-disabled')) 99 $(this).trigger('click'); 100 }); 101})(window.jQuery);
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.