PageSourceSearch

https://www.snydersofhanover.com/wp-content/themes/pfw-wp-snyders-of-hanover/assets/js/product-sizes.js

js snydersofhanover.com collected 2026-09-25 14:07:08 UTC 5,505 bytes, 239 lines download raw bytes

1/* global cscProductSizes */
2
3import isEmpty from 'lodash/isEmpty';
4import wp from 'wp';
5
6const { apiFetch } = wp;
7const { addQueryArgs } = wp.url;
8
9// Set nonce to be able to authenticate our requests in the rest handler in php.
10if (
11	'undefined' !== typeof cscProductSizes &&
12	'undefined' !== typeof cscProductSizes.nonce
13) {
14	apiFetch.use( apiFetch.createNonceMiddleware( cscProductSizes.nonce ) );
15}
16
17// Get Product Sizes selectors.
18const productSizesSelectors = document.querySelectorAll( '.js-product-sizes' );
19
20/**
21 * Parse API response.
22 *
23 * @param {Object} response Response object.
24 * @return {Object|false} Parsed API response. False, otherwise.
25 */
26const parseResponse = response => ( response.ok ? response.json() : false );
27
28/**
29 * Get product data.
30 *
31 * @param {HTMLElement} productSize Product size option.
32 */
33const getProductData = productSize => {
34	if ( !productSize ) {
35		return;
36	}
37
38	const { productData = {} } = productSize.dataset;
39	if ( isEmpty( productData ) ) {
40		return;
41	}
42
43	const parsedProductData = JSON.parse( productData );
44	return parsedProductData;
45};
46
47/**
48 * Update the product nutrition facts panel.
49 *
50 * @param {HTMLElement} productSize Product size option.
51 */
52const updateNutritionFactsPanel = async productSize => {
53	const nutritionFactsPanelElement = document.querySelector(
54		'.js-product-nutrition-facts-panel'
55	);
56
57	if ( !nutritionFactsPanelElement ) {
58		return;
59	}
60
61	const { postId = false } = getProductData( productSize );
62	if ( !postId ) {
63		return;
64	}
65
66	// Persists current panel in case something goes wrong.
67	const oldPanel = nutritionFactsPanelElement.innerHTML;
68
69	// Remove existing panel.
70	nutritionFactsPanelElement.innerHTML = '';
71
72	// Show loading indicator.
73	nutritionFactsPanelElement.classList.add( 'loading' );
74
75	const queryArgs = {
76		product_id: postId // eslint-disable-line camelcase
77	};
78
79	const response = await apiFetch( {
80		path: addQueryArgs( '/csc/v1/nutrition-facts', queryArgs ),
81		parse: false
82	} )
83		.then( response => {
84			return response;
85		} )
86		.catch( error => {
87			nutritionFactsPanelElement.innerHTML = oldPanel;
88
89			// Hide loading indicator.
90			nutritionFactsPanelElement.classList.remove( 'loading' );
91
92			console.log( error ); // eslint-disable-line no-console
93			return error;
94		} );
95
96	const results = await parseResponse( response );
97	if ( results ) {
98		nutritionFactsPanelElement.innerHTML = results;
99
100		// Hide loading indicator.
101		nutritionFactsPanelElement.classList.remove( 'loading' );
102	}
103};
104
105/**
106 * Update the product ingredients list.
107 *
108 * @param {HTMLElement} productSize Product size option.
109 */
110const updateIngredientsList = productSize => {
111	const ingredientsListElement = document.querySelector(
112		'.js-product-ingredients-list'
113	);
114
115	if ( !ingredientsListElement ) {
116		return;
117	}
118
119	const { ingredients = '' } = getProductData( productSize );
120	if ( !isEmpty( ingredients ) ) {
121		ingredientsListElement.innerHTML = ingredients;
122	}
123};
124
125/**
126 * Update the product featured image.
127 *
128 * @param {HTMLElement} productSize Product size option.
129 */
130const updateFeaturedImage = productSize => {
131	const featuredImageElement = document.querySelector(
132		'.js-product-featured-image'
133	);
134
135	if ( !featuredImageElement ) {
136		return;
137	}
138
139	const { featuredImage = '' } = getProductData( productSize );
140	if ( !isEmpty( featuredImage ) ) {
141		featuredImageElement.src = featuredImage;
142	}
143};
144
145/**
146 * Go to product variation featured image.
147 *
148 * @param {HTMLElement} productSize Product size option.
149 */
150const goToGalleryImage = productSize => {
151	const galleryElement = document.querySelector( '.js-product-gallery' );
152	if ( !galleryElement ) {
153		return;
154	}
155
156	const { postId = false } = getProductData( productSize );
157	if ( !postId ) {
158		return;
159	}
160
161	const productGalleryEvent = new CustomEvent( 'productGallery:goTo', {
162		bubbles: true,
163		cancelable: true,
164		detail: { key: 'productId', value: postId }
165	} );
166
167	productSize.dispatchEvent( productGalleryEvent );
168};
169
170/**
171 * Display product status.
172 *
173 * @param {HTMLElement} productSize Product size option.
174 */
175const displayStatus = productSize => {
176	const statusElement = document.querySelector( '.js-product-status' );
177	if ( !statusElement ) {
178		return;
179	}
180
181	const { isDiscontinued = false } = getProductData( productSize );
182
183	if ( isDiscontinued ) {
184		statusElement.innerHTML = cscProductSizes.discontinuedMessage;
185	} else {
186		statusElement.innerHTML = '';
187	}
188};
189
190/**
191 * Update product details based on a product size.
192 *
193 * @param {Object} e The event object.
194 */
195const updateProductDetails = e => {
196	e.preventDefault();
197
198	const { target, detail = {} } = e;
199
200	const productSize = target.options[target.selectedIndex];
201	if ( !productSize ) {
202		return;
203	}
204
205	// Update the nutrition facts panel.
206	updateNutritionFactsPanel( productSize );
207
208	// Update the ingredients list.
209	updateIngredientsList( productSize );
210
211	// Update the featured image.
212	updateFeaturedImage( productSize );
213
214	// Go to product variation featured image.
215	if ( !Object.prototype.hasOwnProperty.call( detail, 'productGalleryIndexChanged' ) ) {
216		goToGalleryImage( productSize );
217	}
218
219	// Display product status.
220	displayStatus( productSize );
221};
222
223/**
224 * Product sizes functionality.
225 */
226export default class ProductSizes {
227	/**
228	 * Constructor.
229	 */
230	constructor() {
231		if ( !productSizesSelectors || 'undefined' === typeof cscProductSizes ) {
232			return;
233		}
234
235		productSizesSelectors.forEach( productSizeSelector => {
236			productSizeSelector.addEventListener( 'change', updateProductDetails );
237		} );
238	}
239}

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.