1const Cart = function () { 2 let productId; 3 let productVariantId; 4 let productUnitId; 5 let productName; 6 let productVariantName; 7 let productCurrency; 8 let productReferer; 9 let productPrice; 10 let addQuantity; 11 let stockQuantity; 12 let isAmountReservation = false; 13 let isPendingQuote = "false"; 14 let orderType; 15 let trailerType; 16 17 return { 18 Update: async function (e) { 19 //NP: clickedButton is not always the button. Sometimes it is the qty input field if [enter] is pressed 20 const clickedButton = e.currentTarget != undefined ? e.currentTarget : e; 21 const form = clickedButton.closest("form"); 22 const quantityField = form.querySelector('[name="Quantity"]'); 23 24 //Setup the form data 25 let formData = new FormData(form); 26 productId = formData.get("ProductId"); 27 productVariantId = formData.get("VariantId"); 28 productUnitId = formData.get("UnitID"); 29 productName = formData.get("ProductName"); 30 productVariantName = formData.get("ProductVariantName"); 31 productCurrency = formData.get("ProductCurrency"); 32 productReferer = formData.get("ProductReferer"); 33 productPrice = formData.get("ProductPrice"); 34 addQuantity = formData.get("Quantity") ? formData.get("Quantity") : 1; 35 stockQuantity = formData.get("Stock") ? formData.get("Stock") : 9999999; 36 isAmountReservation = formData.get("GetReservedAmount") ? formData.get("GetReservedAmount") : "false"; 37 isPendingQuote = formData.get("PendingQuote") ? formData.get("PendingQuote") : "false"; 38 orderType = formData.get("OrderType"); 39 trailerType = formData.get("TrailerType"); 40 41 this.PushDataToGoogleAnalytics(); 42 43 let event = new CustomEvent("update.swift.cart", { 44 //Fire the 'update' event 45 cancelable: true, 46 detail: { 47 formData: formData, 48 parentEvent: e 49 } 50 }); 51 let globalDispatcher = document.dispatchEvent(event); 52 let localDispatcher = clickedButton.dispatchEvent(event); 53 54 if (globalDispatcher != false && localDispatcher != false) { 55 //Remove reserved amount from the form data, so that we only use it for the special reserved amount call 56 if (isAmountReservation == "true") { 57 formData.delete("GetReservedAmount"); 58 } 59 60 //Special call to get only the reserved amount 61 let reservedAmount = 0; 62 if (isAmountReservation == "true" && stockQuantity != 9999999) { 63 reservedAmount = await this.GetReservedAmount(form); 64 } 65 66 const isMinQuantityValid = this.ValidateMinQuantity(quantityField); 67 const isStepQuantityValid = this.ValidateStepQuantity(quantityField); 68 const isValid = isMinQuantityValid && isStepQuantityValid; 69 quantityField.classList.remove("is-invalid"); 70 71 //The actual cart call (add to cart) 72 if (isPendingQuote == "true") { 73 const pendingQuoteMessage = form.querySelector(".js-pending-quote-notice").innerHTML; 74 document.querySelector("#DynamicModalContent").innerHTML = pendingQuoteMessage; 75 76 let dynamicModal = new bootstrap.Modal(document.querySelector('#DynamicModal'), { 77 backdrop: 'static' 78 }); 79 80 dynamicModal.show(); 81 } 82 else if (isValid && (isAmountReservation == "false" || ((parseInt(addQuantity) + parseInt(reservedAmount)) <= parseInt(stockQuantity)))) { 83 //UI updates 84 const clickedButtonWidth = clickedButton.offsetWidth + "px"; 85 86 clickedButton.setAttribute("data-content", clickedButton.innerHTML); 87 clickedButton.style.width = clickedButtonWidth; 88 clickedButton.classList.add("disabled"); 89 clickedButton.disabled = true; 90 clickedButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 512 512"><title>circle-notch</title><g fill="#ffffff"><path d="M288 24.103v8.169a11.995 11.995 0 0 0 9.698 11.768C396.638 63.425 472 150.461 472 256c0 118.663-96.055 216-216 216-118.663 0-216-96.055-216-216 0-104.534 74.546-192.509 174.297-211.978A11.993 11.993 0 0 0 224 32.253v-8.147c0-7.523-6.845-13.193-14.237-11.798C94.472 34.048 7.364 135.575 8.004 257.332c.72 137.052 111.477 246.956 248.531 246.667C393.255 503.711 504 392.789 504 256c0-121.187-86.924-222.067-201.824-243.704C294.807 10.908 288 16.604 288 24.103z"></path></g></svg>'; 91
92 Cart.GetMiniCarts(formData.get("minicartid")).forEach(function (el) { 93 el.classList.add("mini-cart-quantity-added"); 94 }); 95 96 //Fetch 97 const fetchOptions = { 98 method: 'POST', 99 body: formData 100 }; 101 102 let response = await fetch(form.action, fetchOptions); 103 104 if (response.ok) { 105 Cart.Success(response, clickedButton, formData, reservedAmount); 106 } else { 107 Cart.Error(response, clickedButton); 108 } 109 } else if (!isValid) { 110 this.AddToCartValidate(quantityField); 111 } else { 112 const outOfStockMessage = form.querySelector(".js-out-of-stock-notice").innerHTML; 113 document.querySelector("#DynamicModalContent").innerHTML = outOfStockMessage; 114 115 if (quantityField != null) { 116 if (quantityField.min != null) { 117 quantityField.value = quantityField.min > 0 ? quantityField.min : 1; 118 } else { 119 quantityField.value = 1; 120 } 121 } 122 123 let dynamicModal = new bootstrap.Modal(document.querySelector('#DynamicModal'), { 124 backdrop: 'static' 125 }); 126 127 dynamicModal.show(); 128 } 129 } 130 }, 131 132 UpdateOnEnterKey: function (e) { 133 const input = e.currentTarget != undefined ? e.currentTarget : e; 134 e.preventDefault(); 135 136 input.onkeydown = (e) => { 137 if (e.keyCode === 13) { 138 Cart.Update(e); 139 } 140 }; 141 }, 142 143 Success: async function (response, clickedButton, formData, reservedAmount = 0) { 144 let html = await response.text().then(function (text) { 145 return text; 146 }); 147 148 //Fire the 'updated'´event 149 let event = new CustomEvent("updated.swift.cart", { 150 cancelable: true, 151 detail: { 152 formData: formData, 153 html: html 154 } 155 }); 156 let globalDispatcher = document.dispatchEvent(event); 157 let localDispatcher = clickedButton.dispatchEvent(event); 158 159 if (globalDispatcher != false && localDispatcher != false) { 160 //Cleanup 161 clickedButton.classList.remove("disabled"); 162 clickedButton.style.width = ""; 163 clickedButton.disabled = false; 164 clickedButton.innerHTML = clickedButton.getAttribute("data-content"); 165 clickedButton.setAttribute("data-content", ""); 166 167 let removeFocusCssClassTimer = setTimeout(function () { 168 Cart.GetMiniCarts(formData.get("minicartid")).forEach(function (el) { 169 el.classList.remove("mini-cart-quantity-added"); 170 }); 171 }, 200); 172 173 //Replace the markup (Update min carts counters) 174 let totalQuantity = html != undefined ? html : 0; 175 Cart.GetMiniCarts(formData.get("minicartid")).forEach(function (el) { 176 el.innerHTML = "(" + totalQuantity.trim() + ")"; 177 }); 178 179 //Update stock 180 if (isAmountReservation == "true") { 181 this.UpdateStock(reservedAmount, clickedButton) 182 } 183 } 184 }, 185 186 Error: async function (response, clickedButton) { 187 //Cleanup 188 let removeFocusCssClassTimer = setTimeout(function () { 189 document.querySelectorAll(".js-cart-qty").forEach(function (el) { 190 el.classList.remove("mini-cart-quantity-added"); 191 }); 192 }, 200); 193 194 clickedButton.classList.remove("disabled"); 195 clickedButton.style.width = ""; 196 clickedButton.disabled = false; 197 clickedButton.innerHTML = '<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 512 512"><title>circle-notch</title><g fill="#ffffff"><path d="M288 24.103v8.169a11.995 11.995 0 0 0 9.698 11.768C396.638 63.425 472 150.461 472 256c0 118.663-96.055 216-216 216-118.663 0-216-96.055-216-216 0-104.534 74.546-192.509 174.297-211.978A11.993 11.993 0 0 0 224 32.253v-8.147c0-7.523-6.845-13.193-14.237-11.798C94.472 34.048 7.364 135.575 8.004 257.332c.72 137.052 111.477 246.956 248.531 246.667C393.255 503.711 504 392.789 504 256c0-121.187-86.924-222.067-201.824-243.704C294.807 10.908 288 16.604 288 24.103z"></path></g></svg>'; 198 }, 199 200 PushDataToGoogleAnalytics: function() { 201 if (typeof gtag !== "undefined") { 202 gtag("event", "add_to_cart", { 203 currency: productCurrency, 204 value: productPrice, 205 items: [ 206 { 207 item_id: productId, 208 item_name: productName, 209 item_variant: productVariantName, 210 currency: productCurrency, 211 item_list_id: productReferer, 212 price: productPrice, 213 quantity: addQuantity, 214 item_category: orderType, 215 item_category2: trailerType 216 } 217 ] 218 }); 219 } 220 }, 221 222 GetMiniCarts: function (miniCartId) { 223 let miniCarts = []; 224 225 if (miniCartId != null) { 226 const miniCartElement = document.querySelector("#Cart_" + miniCartId); 227 228 if (miniCartElement) { 229 miniCarts = [miniCartElement]; 230 } else { 231 console.log("Mini cart page is missing"); 232 } 233 } else { 234 miniCarts = document.querySelectorAll(".js-cart-qty"); 235 } 236 237 return miniCarts; 238 }, 239 240 GetReservedAmount: async function (form) { 241 const getReservedFormData = new FormData(); 242 getReservedFormData.append("GetReservedAmount", true); 243 getReservedFormData.append("ProductId", productId); 244 245 if (addQuantity != null) { 246 getReservedFormData.append("Quantity", addQuantity); 247 } 248 249 if (productUnitId != null) { 250 getReservedFormData.append("UnitId", productUnitId); 251 } 252 253 if (productVariantId != null) { 254 getReservedFormData.append("VariantId", productVariantId); 255 } 256 257 const getReservedAmountfetchOptions = { 258 method: 'POST', 259 body: getReservedFormData 260 }; 261 262 let response = await fetch(form.action, getReservedAmountfetchOptions); 263 264 if (response.ok) { 265 let amount = await response.text().then(function (text) { 266 return text; 267 }); 268 269 return amount; 270 } else { 271 Cart.Error(response, clickedButton); 272 273 return 0; 274 } 275 }, 276 277 UpdateStock: function (reservedAmount, clickedButton) {
278 const stockLevelElement = clickedButton.closest(".js-product") ? clickedButton.closest(".js-product").querySelector(".js-text-stock") : clickedButton.closest("#content").querySelector(".js-text-stock"); 279 280 if (stockLevelElement) { 281 if (stockQuantity != 9999999) { 282 stockLevelElement.innerHTML = (parseInt(stockQuantity) - parseInt(addQuantity) - parseInt(reservedAmount)); 283 } 284 } 285 }, 286 287 ValidateMinQuantity: function (quantityField) { 288 let isValid = true; 289 290 if (quantityField != null) { 291 const quantity = parseInt(quantityField.value); 292 const minQuantity = parseInt(quantityField.min); 293 isValid = quantity < minQuantity ? false : isValid; 294 } 295 296 return isValid; 297 }, 298 299 ValidateStepQuantity: function (quantityField) { 300 let isValid = true; 301 302 if (quantityField != null) { 303 isValid = quantityField.checkValidity(); 304 } 305 306 return isValid; 307 }, 308 309 AddToCartValidate: function (event) { 310 let quantityField = event.currentTarget != undefined ? event.currentTarget : event; 311 const form = quantityField.closest("form"); 312 313 const minQuantityWarning = form.querySelector(".js-min-quantity-warning"); 314 const stepQuantityWarning = form.querySelector(".js-step-quantity-warning"); 315 316 const isMinQuantityValid = this.ValidateMinQuantity(quantityField); 317 const isStepQuantityValid = this.ValidateStepQuantity(quantityField); 318 const isValid = isMinQuantityValid && isStepQuantityValid; 319 320 const dynamicModal = new bootstrap.Modal(document.querySelector('#DynamicModal'), { }); 321 322 if (!isMinQuantityValid && minQuantityWarning) { 323 const message = minQuantityWarning.innerHTML; 324 const minQuantity = parseInt(quantityField.min); 325 document.querySelector("#DynamicModalContent").innerHTML = message; 326 327 if (!document.querySelector('#DynamicModal').classList.contains("show")) { 328 dynamicModal.show(); 329 } 330 331 if (form.querySelector('[name="Quantity"]')) { 332 form.querySelector('[name="Quantity"]').value = minQuantity; 333 } 334 } 335 336 if (!isStepQuantityValid && stepQuantityWarning) { 337 const message = stepQuantityWarning.innerHTML; 338 document.querySelector("#DynamicModalContent").innerHTML = message; 339 340 if (!document.querySelector('#DynamicModal').classList.contains("show")) { 341 dynamicModal.show(); 342 } 343 } 344 345 if (!isValid) { 346 quantityField.classList.add("is-invalid"); 347 } else { 348 quantityField.classList.remove("is-invalid"); 349 } 350 } 351 } 352}(); 353 354export { Cart };
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.