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 $( this ).append( 126 '<button type="button" class="show-password-input" aria-label="' + 127 woocommerce_params.i18n_password_show + 128 '" aria-describedBy="' + 129 describedBy + 130 '"></button>' 131 ); 132 } ); 133 134 $( '.show-password-input' ).on( 'click', function ( event ) { 135 event.preventDefault(); 136 137 if ( $( this ).hasClass( 'display-password' ) ) { 138 $( this ).removeClass( 'display-password' ); 139 $( this ).attr( 140 'aria-label', 141 woocommerce_params.i18n_password_show 142 ); 143 } else { 144 $( this ).addClass( 'display-password' ); 145 $( this ).attr( 146 'aria-label', 147 woocommerce_params.i18n_password_hide 148 ); 149 } 150 if ( $( this ).hasClass( 'display-password' ) ) { 151 $( this ) 152 .siblings( [ 'input[type="password"]' ] ) 153 .prop( 'type', 'text' ); 154 } else { 155 $( this ) 156 .siblings( 'input[type="text"]' ) 157 .prop( 'type', 'password' ); 158 } 159 160 $( this ).siblings( 'input' ).focus(); 161 } ); 162 163 $( 'a.coming-soon-footer-banner-dismiss' ).on( 'click', function ( e ) { 164 var target = $( e.target ); 165 $.ajax( { 166 type: 'post', 167 url: target.data( 'rest-url' ), 168 data: { 169 woocommerce_meta: { 170 coming_soon_banner_dismissed: 'yes', 171 }, 172 }, 173 beforeSend: function ( xhr ) { 174 xhr.setRequestHeader( 175 'X-WP-Nonce', 176 target.data( 'rest-nonce' ) 177 ); 178 },
179 complete: function () { 180 $( '#coming-soon-footer-banner' ).hide(); 181 }, 182 } ); 183 } ); 184 185 // If the "Enable AJAX add to cart buttons on archives" setting is disabled 186 // the add-to-cart.js file won't be loaded, so we need to add the event listener here. 187 if ( typeof wc_add_to_cart_params === 'undefined' ) { 188 $( document.body ).on( 189 'keydown', 190 '.remove_from_cart_button', 191 on_keydown_remove_from_cart 192 ); 193 } 194 195 $( document.body ).on( 196 'item_removed_from_classic_cart updated_wc_div', 197 focus_populate_live_region 198 ); 199} ); 200 201/** 202 * Handle when pressing the Space key on the remove item link. 203 * This is necessary because the link has the role="button" attribute 204 * and needs to act like a button. 205 */ 206function on_keydown_remove_from_cart( event ) { 207 if ( event.key === ' ' ) { 208 event.preventDefault(); 209 event.currentTarget.click(); 210 } 211} 212 213/** 214 * Focus on the first notice element on the page. 215 * 216 * Populated live regions don't always are announced by screen readers. 217 * This function focus on the first notice message with the role="alert" 218 * attribute to make sure it's announced. 219 */ 220function focus_populate_live_region() { 221 var noticeClasses = [ 222 'woocommerce-message', 223 'woocommerce-error', 224 'wc-block-components-notice-banner', 225 ]; 226 var noticeSelectors = noticeClasses 227 .map( function ( className ) { 228 return '.' + className + '[role="alert"]'; 229 } ) 230 .join( ', ' ); 231 var noticeElements = document.querySelectorAll( noticeSelectors ); 232 233 if ( noticeElements.length === 0 ) { 234 return; 235 } 236 237 var firstNotice = noticeElements[ 0 ]; 238 239 firstNotice.setAttribute( 'tabindex', '-1' ); 240 241 // Wait for the element to get the tabindex attribute so it can be focused. 242 var delayFocusNoticeId = setTimeout( function () { 243 firstNotice.focus(); 244 clearTimeout( delayFocusNoticeId ); 245 }, 500 ); 246} 247 248/** 249 * Refresh the sorted by live region. 250 * 251 * Skips when the Interactivity API product filters are present on the page, 252 * as those manage the result count updates themselves. 253 */ 254function refresh_sorted_by_live_region() { 255 var sorted_by_live_region = document.querySelector( 256 '.woocommerce-result-count' 257 ); 258 var hasInteractivityFilters = document.querySelector( 259 '[data-wp-interactive="woocommerce/product-filters"]' 260 ); 261 262 if ( 263 ! sorted_by_live_region || 264 ! window.location.search || 265 hasInteractivityFilters 266 ) { 267 return; 268 } 269 270 var text = sorted_by_live_region.innerHTML; 271 sorted_by_live_region.setAttribute( 'role', 'alert' ); 272 sorted_by_live_region.setAttribute( 'aria-hidden', 'true' ); 273 274 var sorted_by_live_region_id = setTimeout( function () { 275 sorted_by_live_region.setAttribute( 'aria-hidden', 'false' ); 276 sorted_by_live_region.innerHTML = ''; 277 sorted_by_live_region.innerHTML = text; 278 clearTimeout( sorted_by_live_region_id ); 279 }, 2000 ); 280} 281 282function on_document_ready() { 283 focus_populate_live_region(); 284 refresh_sorted_by_live_region(); 285} 286 287document.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.