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.