1/* global Cookies */ 2jQuery( function ( $ ) { 3 // Orderby 4 $( '.woocommerce-ordering' ).on( 'change', 'select.orderby', function () { 5 $( this ).closest( 'form' ).trigger( 'submit' ); 6 } ); 7 8 // Target quantity inputs on product pages 9 $( 'input.qty:not(.product-quantity input.qty)' ).each( function () { 10 var min = parseFloat( $( this ).attr( 'min' ) ); 11 12 if ( min >= 0 && parseFloat( $( this ).val() ) < min ) { 13 $( this ).val( min ); 14 } 15 } ); 16 17 var noticeID = $( '.woocommerce-store-notice' ).data( 'noticeId' ) || '', 18 cookieName = 'store_notice' + noticeID; 19 20 // Check the value of that cookie and show/hide the notice accordingly 21 if ( 'hidden' === Cookies.get( cookieName ) ) { 22 $( '.woocommerce-store-notice' ).hide(); 23 } else { 24 $( '.woocommerce-store-notice' ).show(); 25 /** 26 * After adding the role="button" attribute to the 27 * .woocommerce-store-notice__dismiss-link element, 28 * we need to add the keydown event listener to it. 29 */ 30 function store_notice_keydown_handler( event ) { 31 if ( [ 'Enter', ' ' ].includes( event.key ) ) { 32 event.preventDefault(); 33 $( '.woocommerce-store-notice__dismiss-link' ).click(); 34 } 35 } 36 37 // Set a cookie and hide the store notice when the dismiss button is clicked 38 function store_notice_click_handler( event ) { 39 Cookies.set( cookieName, 'hidden', { path: '/' } ); 40 $( '.woocommerce-store-notice' ).hide(); 41 event.preventDefault(); 42 $( '.woocommerce-store-notice__dismiss-link' ) 43 .off( 'click', store_notice_click_handler ) 44 .off( 'keydown', store_notice_keydown_handler ); 45 } 46 47 $( '.woocommerce-store-notice__dismiss-link' ) 48 .on( 'click', store_notice_click_handler ) 49 .on( 'keydown', store_notice_keydown_handler ); 50 } 51 52 // Make form field descriptions toggle on focus. 53 if ( $( '.woocommerce-input-wrapper span.description' ).length ) { 54 $( document.body ).on( 'click', function () { 55 $( '.woocommerce-input-wrapper span.description:visible' ) 56 .prop( 'aria-hidden', true ) 57 .slideUp( 250 ); 58 } ); 59 } 60 61 $( '.woocommerce-input-wrapper' ).on( 'click', function ( event ) { 62 event.stopPropagation(); 63 } ); 64 65 $( '.woocommerce-input-wrapper :input' ) 66 .on( 'keydown', function ( event ) { 67 var input = $( this ), 68 parent = input.parent(), 69 description = parent.find( 'span.description' ); 70 71 if ( 72 27 === event.which && 73 description.length && 74 description.is( ':visible' ) 75 ) { 76 description.prop( 'aria-hidden', true ).slideUp( 250 ); 77 event.preventDefault(); 78 return false; 79 } 80 } ) 81 .on( 'click focus', function () { 82 var input = $( this ), 83 parent = input.parent(), 84 description = parent.find( 'span.description' ); 85 86 parent.addClass( 'currentTarget' ); 87 88 $( 89 '.woocommerce-input-wrapper:not(.currentTarget) span.description:visible' 90 ) 91 .prop( 'aria-hidden', true ) 92 .slideUp( 250 ); 93 94 if ( description.length && description.is( ':hidden' ) ) { 95 description.prop( 'aria-hidden', false ).slideDown( 250 ); 96 } 97 98 parent.removeClass( 'currentTarget' ); 99 } ); 100 101 // Common scroll to element code. 102 $.scroll_to_notices = function ( scrollElement ) { 103 if ( scrollElement.length ) { 104 $( 'html, body' ).animate( 105 { 106 scrollTop: scrollElement.offset().top - 100, 107 }, 108 1000 109 ); 110 } 111 }; 112 113 // Show password visibility hover icon on woocommerce forms 114 $( '.woocommerce form .woocommerce-Input[type="password"]' ).wrap( 115 '<span class="password-input"></span>' 116 ); 117 // Add 'password-input' class to the password wrapper in checkout page. 118 $( '.woocommerce form input' ) 119 .filter( ':password' ) 120 .parent( 'span' ) 121 .addClass( 'password-input' ); 122 123 $( '.password-input' ).each( function () { 124 const describedBy = $( this ).find( 'input' ).attr( 'id' ); 125 const $button = $( '<button>', { 126 type: 'button', 127 class: 'show-password-input', 128 'aria-label': woocommerce_params.i18n_password_show, 129 } ); 130 131 $button.attr( 'aria-describedby', describedBy ); 132 $( this ).append( $button ); 133 } ); 134 135 $( '.show-password-input' ).on( 'click', function ( event ) { 136 event.preventDefault(); 137 138 if ( $( this ).hasClass( 'display-password' ) ) { 139 $( this ).removeClass( 'display-password' ); 140 $( this ).attr( 141 'aria-label', 142 woocommerce_params.i18n_password_show 143 ); 144 } else { 145 $( this ).addClass( 'display-password' ); 146 $( this ).attr( 147 'aria-label', 148 woocommerce_params.i18n_password_hide 149 ); 150 } 151 if ( $( this ).hasClass( 'display-password' ) ) { 152 $( this ) 153 .siblings( [ 'input[type="password"]' ] ) 154 .prop( 'type', 'text' ); 155 } else { 156 $( this ) 157 .siblings( 'input[type="text"]' ) 158 .prop( 'type', 'password' ); 159 } 160 161 $( this ).siblings( 'input' ).trigger( 'focus' ); 162 } ); 163 164 $( 'a.coming-soon-footer-banner-dismiss' ).on( 'click', function ( e ) { 165 var target = $( e.target ); 166 $.ajax( { 167 type: 'post', 168 url: target.data( 'rest-url' ), 169 data: { 170 woocommerce_meta: { 171 coming_soon_banner_dismissed: 'yes', 172 }, 173 }, 174 beforeSend: function ( xhr ) { 175 xhr.setRequestHeader( 176 'X-WP-Nonce', 177 target.data( 'rest-nonce' ) 178 ); 179 },
180 complete: function () { 181 $( '#coming-soon-footer-banner' ).hide(); 182 }, 183 } ); 184 } ); 185 186 // If the "Enable AJAX add to cart buttons on archives" setting is disabled 187 // the add-to-cart.js file won't be loaded, so we need to add the event listener here. 188 if ( typeof wc_add_to_cart_params === 'undefined' ) { 189 $( document.body ).on( 190 'keydown', 191 '.remove_from_cart_button', 192 on_keydown_remove_from_cart 193 ); 194 } 195 196 $( document.body ).on( 197 'item_removed_from_classic_cart updated_wc_div', 198 focus_populate_live_region 199 ); 200} ); 201 202/** 203 * Handle when pressing the Space key on the remove item link. 204 * This is necessary because the link has the role="button" attribute 205 * and needs to act like a button. 206 */ 207function on_keydown_remove_from_cart( event ) { 208 if ( event.key === ' ' ) { 209 event.preventDefault(); 210 event.currentTarget.click(); 211 } 212} 213 214/** 215 * Focus on the first notice element on the page. 216 * 217 * Populated live regions don't always are announced by screen readers. 218 * This function focus on the first notice message with the role="alert" 219 * attribute to make sure it's announced. 220 */ 221function focus_populate_live_region() { 222 var noticeClasses = [ 223 'woocommerce-message', 224 'woocommerce-error', 225 'wc-block-components-notice-banner', 226 ]; 227 var noticeSelectors = noticeClasses 228 .map( function ( className ) { 229 return '.' + className + '[role="alert"]'; 230 } ) 231 .join( ', ' ); 232 var noticeElements = document.querySelectorAll( noticeSelectors ); 233 234 if ( noticeElements.length === 0 ) { 235 return; 236 } 237 238 var firstNotice = noticeElements[ 0 ]; 239 240 firstNotice.setAttribute( 'tabindex', '-1' ); 241 242 // Wait for the element to get the tabindex attribute so it can be focused. 243 var delayFocusNoticeId = setTimeout( function () { 244 firstNotice.focus(); 245 clearTimeout( delayFocusNoticeId ); 246 }, 500 ); 247} 248 249/** 250 * Refresh the sorted by live region. 251 * 252 * Skips when the Interactivity API product filters are present on the page, 253 * as those manage the result count updates themselves. 254 */ 255function refresh_sorted_by_live_region() { 256 var sorted_by_live_region = document.querySelector( 257 '.woocommerce-result-count' 258 ); 259 var hasInteractivityFilters = document.querySelector( 260 '[data-wp-interactive="woocommerce/product-filters"]' 261 ); 262 263 if ( 264 ! sorted_by_live_region || 265 ! window.location.search || 266 hasInteractivityFilters 267 ) { 268 return; 269 } 270 271 var text = sorted_by_live_region.innerHTML; 272 sorted_by_live_region.setAttribute( 'role', 'alert' ); 273 sorted_by_live_region.setAttribute( 'aria-hidden', 'true' ); 274 275 var sorted_by_live_region_id = setTimeout( function () { 276 sorted_by_live_region.setAttribute( 'aria-hidden', 'false' ); 277 sorted_by_live_region.innerHTML = ''; 278 sorted_by_live_region.innerHTML = text; 279 clearTimeout( sorted_by_live_region_id ); 280 }, 2000 ); 281} 282 283function on_document_ready() { 284 focus_populate_live_region(); 285 refresh_sorted_by_live_region(); 286} 287 288document.addEventListener( 'DOMContentLoaded', on_document_ready );
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.