PageSourceSearch

https://www.sareflexology.org.za/wp-content/plugins/woocommerce/assets/js/frontend/woocommerce.js?ver=10.8.1

js sareflexology.org.za collected 2026-10-03 00:54:05 UTC 7,976 bytes, 287 lines download raw bytes

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.