1jQuery(function($) { 2 $.datepicker.regional['fr'] = { 3 closeText: 'Fermer', 4 prevText: '<Préc', 5 nextText: 'Suiv>', 6 currentText: 'Aujourd\'hui', 7 monthNames: ['Janvier','Février','Mars','Avril','Mai','Juin', 8 'Juillet','Août','Septembre','Octobre','Novembre','Décembre'], 9 monthNamesShort: ['Janvier','Février','Mars','Avril','Mai','Juin', 10 'Juillet','Août','Septembre','Octobre','Novembre','Décembre'], 11 dayNames: ['Dimanche','Lundi','Mardi','Mercredi','Jeudi','Vendredi','Samedi'], 12 dayNamesShort: ['Dim.','Lun.','Mar.','Mer.','Jeu.','Ven.','Sam.'], 13 dayNamesMin: ['dim','lun','mar','mer','jeu','ven','sam'], 14 weekHeader: 'Sem.', 15 dateFormat: 'dd/mm/yy', 16 firstDay: 1, 17 isRTL: false, 18 showMonthAfterYear: false, 19 yearSuffix: '' 20 }; 21 $.datepicker.setDefaults( $.datepicker.regional['fr'] ); 22}); 23 24jQuery(document).ready(function ($) { 25 26 // âââââââââââââââââââââââââââââââââââââââââââââ 27 // Initialisation de chaque champ inventory_slots 28 // âââââââââââââââââââââââââââââââââââââââââââââ 29 30 // âââ Premier chargement âââ 31 $('.gf-inventory-date').each(function () { 32 let $input = $(this); 33 let $wrapper = $input.closest('.ginput_container'); 34 initDatePicker( $input ); 35 restoreState( $wrapper ); 36 }); 37 38 // âââ Après chaque re-render GF (pagination, erreurâ¦) âââ 39 $(document).on('gform_post_render', function () { 40 41 $('.gf-inventory-date').each(function () { 42 let $input = $(this); 43 let $wrapper = $input.closest('.ginput_container'); 44 initDatePicker( $input ); 45 restoreState( $wrapper ); 46 }); 47 }); 48 49 // âââââââââââââââââââââââââââââââââââââââââââââ 50 // Initialisation du datepicker 51 // âââââââââââââââââââââââââââââââââââââââââââââ 52 53 function initDatePicker( $input ) { 54 55 if ( $input.hasClass('hasDatepicker') ) return; 56 57 let fieldId = $input.data('field-id'); 58 let formId = $input.data('form-id'); 59 let slotsData = []; 60 let availableDates = []; 61 62 try { 63 slotsData = JSON.parse( $input.attr('data-slots') || '[]' ); 64 availableDates = slotsData.map(d => d.date); 65 } catch (e) { 66 console.warn('gf-inventory : impossible de parser data-slots', e); 67 } 68 69 let $wrapper = $input.closest('.ginput_container'); 70 71 let slots = []; 72 try { 73 slots = JSON.parse( $input.data('slots') || '[]' ); 74 } catch(e) { 75 slots = []; 76 } 77 78 let defaultDate = null; 79 if ( slotsData.length ) { 80 let today = new Date(); 81 today.setHours(0,0,0,0); 82 let futureDates = slotsData 83 .map(d => new Date(d.date + 'T00:00:00')) 84 .filter(d => d >= today) 85 .sort((a, b) => a - b); 86 if ( futureDates.length ) { 87 let diffMs = futureDates[0].getTime() - today.getTime(); 88 let diffDays = Math.round( diffMs / (1000 * 60 * 60 * 24) ); 89 defaultDate = diffDays; 90 } 91 } 92 93 $input.datepicker({ 94 dateFormat: 'dd/mm/yy', 95 defaultDate: defaultDate, 96 minDate: 0, 97 changeMonth: true, 98 changeYear: true, 99 yearRange: 'c:c+20', 100 101 beforeShow: function (input, inst) { 102 $(inst.dpDiv).addClass('gf-inventory-datepicker gform-theme-datepicker gravity-theme'); 103 // console.log($.datepicker.regional) 104 if ( $.datepicker.regional && $.datepicker.regional['fr'] ) { 105 // console.log($.datepicker.regional) 106 $.datepicker.setDefaults( $.datepicker.regional['fr'] ); 107 } 108 }, 109 110 onClose: function (dateText, inst) { 111 $(inst.dpDiv).removeClass('gf-inventory-datepicker'); 112 }, 113 114 beforeShowDay: function (date) { 115 let d = $.datepicker.formatDate('yy-mm-dd', date); 116 if ( availableDates.includes(d) ) { 117 return [true, 'available-date', 'Disponible']; 118 } 119 return [false, '', 'Non disponible']; 120 }, 121 122 onSelect: function (dateText) { 123 let dateObj = $(this).datepicker('getDate'); 124 let isoDate = $.datepicker.formatDate('yy-mm-dd', dateObj); 125 126 $wrapper.find('.gf-date-value').val(isoDate); 127 $wrapper.find('.gf-main-value').val(isoDate); 128 $wrapper.find('.gf-slot-value').val(''); 129 resetQty( $wrapper ); 130 loadSlots( $input, formId, fieldId, isoDate ); 131 132 $wrapper.find('.gf-qty').trigger('change'); 133 } 134 }); 135 136 $input.on('keydown', function (e) { 137 if ( e.key === 'Backspace' || e.key === 'Delete' ) { 138 $input.val(''); 139 $wrapper.find('.gf-date-value').val(''); 140 $wrapper.find('.gf-slot-value').val(''); 141 $wrapper.find('.gf-main-value').val(''); 142 $wrapper.find('.gf-inventory-slots').empty(); 143 resetQty( $wrapper ); 144 $input.datepicker('setDate', null); 145 } 146 }); 147 } 148 149 // âââââââââââââââââââââââââââââââââââââââââââââ 150 // Gestion de la quantité 151 // âââââââââââââââââââââââââââââââââââââââââââââ 152 153 function resetQty( $wrapper ) { 154 $wrapper.find('.gf-qty-wrapper') 155 .hide() 156 .find('input') 157 .prop('disabled', true) 158 .val(''); 159 } 160 161 function enableQty( $wrapper, max, min, stockTitle ) { 162 min = min || 1; 163 let label = stockTitle && stockTitle.trim() !== '' ? stockTitle : 'Quantité'; 164 $wrapper.find('.gf-qty-wrapper').find('.gfield_label').text( label ); 165 $wrapper.find('.gf-qty') 166 .attr('max', max) 167 .attr('min', min) 168 .val('') 169 .prop('disabled', false); 170 $wrapper.find('.gf-qty-wrapper').show(); 171 } 172 173 // âââââââââââââââââââââââââââââââââââââââââââââ 174 // Restauration de l'état post-erreur / pagination 175 // âââââââââââââââââââââââââââââââââââââââââââââ 176 177 function restoreState( $wrapper ) { 178 let $input = $wrapper.find('.gf-inventory-date'); 179 let date = $input.data('restore-date') || $wrapper.find('.gf-date-value').val(); 180 let slot = $wrapper.find('.gf-slot-value').val(); 181 let qty = parseInt( $wrapper.find('.gf-qty').val() ) || 1; 182 183 if ( ! date ) return; 184 185 loadSlots( 186 $input, 187 $input.data('form-id'), 188 $input.data('field-id'), 189 date, 190 function () { 191 let formatted = $.datepicker.formatDate('dd/mm/yy', new Date(date)); 192 $input.val(formatted); 193 194 if ( slot ) { 195 let $radio = $wrapper.find(`input[type="radio"][value="${slot}"]`); 196 if ( $radio.length ) { 197 $radio.prop('checked', true).trigger('change'); 198 } 199 } 200 201 if ( qty > 0 ) { 202 $wrapper.find('.gf-qty').val(qty); 203 $wrapper.find('.gf-qty').trigger('gf-qty-restore'); 204 } 205 } 206 ); 207 } 208 209 // âââââââââââââââââââââââââââââââââââââââââââââ 210 // Chargement AJAX des créneaux 211 // âââââââââââââââââââââââââââââââââââââââââââââ 212 213 function loadSlots( $input, formId, fieldId, date, callback ) { 214 let $wrapper = $input.closest('.ginput_container'); 215 let $container = $wrapper.find('.gf-inventory-slots'); 216 217 $container.html('<p>Chargementâ¦</p>'); 218 219 $.post( 220 gfInventory.ajax_url, 221 { 222 action: 'get_slots', 223 nonce: gfInventory.nonce, 224 form_id: formId, 225 field_id: fieldId, 226 date: date, 227 }, 228 function (response) { 229 renderSlots( $container, response, formId, fieldId ); 230 if ( typeof callback === 'function' ) callback(); 231 } 232 ).fail(function () { 233 $container.html('<p>Erreur lors du chargement des créneaux.</p>'); 234 }); 235 } 236 237 // âââââââââââââââââââââââââââââââââââââââââââââ 238 // Rendu des créneaux 239 // âââââââââââââââââââââââââââââââââââââââââââââ 240
241 function renderSlots( $container, slots, formId, fieldId ) { 242 243 if ( ! slots || ! slots.length ) { 244 $container.html('<p style="color:#c92c2c; font-style:italic;">Aucun créneau disponible</p>'); 245 return; 246 } 247 248 $container.empty(); 249 250 let radioName = `gf_slot_${formId}_${fieldId}`; 251 252 slots.forEach(function (slot) { 253 254 let stock = parseInt(slot.stock || 0); 255 let isSoldOut = stock <= 0; 256 let title = slot.stockTitle ? ' ' + slot.stockTitle : ''; 257 let label = slot.stockLabel ? ' ' + slot.stockLabel : ''; 258 let remaining = stock; 259 let total = parseInt(slot.stockTotal || stock); 260 261 let $slot = $(` 262 <div class="gf-slot ${isSoldOut ? 'soldout' : ''}" data-max="${remaining}" data-min="${slot.min || 1}" data-stock-title="${slot.stockTitle ?? ''}"> 263 <label> 264 <input 265 type="radio" 266 name="${radioName}" 267 value="${slot.label}" 268 ${isSoldOut ? 'disabled' : ''} 269 > 270 ${slot.label} 271 ${isSoldOut 272 ? `<span class="gf-stock-notice" style="color:#c92c2c; font-style:italic; font-weight:400;"> 273 ${slot.noticeSoldOut || 'Complet'} 274 </span>` 275 : slot.displayStock 276 ? `<span class="gf-stock-label" style="color:#c92c2c; font-style:italic; font-weight:400;"> 277 ${remaining}/${total}${label} 278 </span>` 279 : '' 280 } 281 </label> 282 </div> 283 `); 284 285 $container.append($slot); 286 }); 287 288 // ââ Sélection d'un créneau ââ 289 $container.on('change', 'input[type="radio"]', function () { 290 let $wrapper = $container.closest('.ginput_container'); 291 let $slotDiv = $(this).closest('.gf-slot'); 292 let max = parseInt( $slotDiv.data('max') || 9999 ); 293 let min = parseInt( $slotDiv.data('min') || 1 ); 294 let stockTitle = $slotDiv.data('stock-title') || ''; 295 296 $container.find('.gf-slot').removeClass('selected'); 297 $slotDiv.addClass('selected'); 298 299 $wrapper.find('.gf-slot-value').val( $(this).val() ); 300 $wrapper.find('.gf-main-value').val( 301 $wrapper.find('.gf-date-value').val() + '|' + $(this).val() 302 ); 303 304 enableQty( $wrapper, max, min, stockTitle ); 305 306 $wrapper.find('.gf-qty').val('').trigger('change'); 307 }); 308 309 // ââ Validation de la quantité ââ 310 $container.on('input', '.gf-qty', function () { 311 let max = parseInt( $(this).attr('max') || 9999 ); 312 let val = parseInt( $(this).val() || 1 ); 313 314 if ( val > max ) { 315 $(this).val(max); 316 showQtyError( $(this), 'Veuillez saisir un nombre ⤠' + max ); 317 } else if ( val < 1 ) { 318 $(this).val(1); 319 clearQtyError( $(this) ); 320 } else { 321 clearQtyError( $(this) ); 322 } 323 }); 324 } 325 326 // âââââââââââââââââââââââââââââââââââââââââââââ 327 // Messages d'erreur inline sur la quantité 328 // âââââââââââââââââââââââââââââââââââââââââââââ 329 330 function showQtyError( $input, message ) { 331 let $wrapper = $input.closest('.gf-qty-wrapper'); 332 let $error = $wrapper.find('.gf-qty-error'); 333 334 if ( ! $error.length ) { 335 $error = $('<span class="gf-qty-error" style="color:red; font-size:.875em;"></span>'); 336 $wrapper.append($error); 337 } 338 $error.text(message); 339 } 340 341 function clearQtyError( $input ) { 342 $input.closest('.gf-qty-wrapper').find('.gf-qty-error').remove(); 343 } 344 345});
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.