1/* global $ */ 2/* global postData */ 3/* global API_ENDPOINT_ADD_TO_CART */ 4/* global throwError */ 5/* global handleError */ 6 7const API_ENDPOINT_ADD_COMBO = window.location.origin + '/api/shopping/v1/cart/combos/add.json'; 8 9document.addEventListener("DOMContentLoaded", function (event) { 10 "use strict"; 11 12 let comboKeeper = { 13 combos: {}, 14 15 addToCart: function(comboId, $modal = null) { 16 if (this.hasOwnProperty("combos") && this.combos.hasOwnProperty(comboId)) { 17 let quantity = $(`input[type="number"][name="${comboId}"]`).val(); 18 if (!quantity) { 19 quantity = 1; 20 } 21 22 postData(API_ENDPOINT_ADD_COMBO, { 23 combo_id: comboId, 24 quantity: quantity, 25 options: comboKeeper.combos[comboId].options 26 }).then(response => { 27 if (response.hasOwnProperty("success") && response.success) { 28 if ($modal) { 29 $modal.find(".success").show(); 30 $modal.find(".add-to-cart-button").addClass("btn-dark").addClass("disabled"). 31 removeClass("btn-primary").attr("disabled", "disabled"). 32 html(LABEL_ALREADY_IN_CART); 33 } 34 $(`.add-combo[data-combo-id="${comboId}"]`).addClass("btn-dark").removeClass("btn-primary"). 35 attr("disabled", "disabled").html(LABEL_ALREADY_IN_CART); 36 } else { 37 handleError(response, "combo"); 38 } 39 40 let added = {}; 41 if (response.hasOwnProperty("added")) { 42 added = response.added; 43 } 44 document.dispatchEvent(new CustomEvent('oecommerce-added-combo', { 45 detail: { 46 added: added 47 } 48 })); 49 50 let cartResponse = {}; 51 if (response.cart) { 52 cartResponse = response.cart; 53 } 54 55 document.dispatchEvent(new CustomEvent('oecommerce-update-ui', { 56 detail: { 57 reload: false, 58 cart: cartResponse 59 } 60 })); 61 }); 62 } else { 63 throwError(`Attempted to add comboId ${comboId} but it does not exist in comboKeeper.`); 64 } 65 }, 66 67 init: function() { 68 $(".combo-modals").each(function () { 69 let $combo = $(this); 70 let comboId = $combo.attr("data-combo-id"); 71 if (!comboId) { 72 throwError("No combo ID specified on combo collection."); 73 } 74 if (!comboKeeper.combos.hasOwnProperty(comboId)) { 75 comboKeeper.combos[comboId] = {}; 76 comboKeeper.combos[comboId].options = {}; 77 } 78 comboKeeper.combos[comboId].$modals = $combo.find(".modal"); 79 comboKeeper.setupModals(comboId); 80 }); 81 82 $("button.add-combo").on("click", function () { 83 let $button = $(this); 84 let comboId = $button.attr("data-combo-id"); 85 if (!comboId) { 86 throwError("No combo ID specified on combo add to cart button."); 87 } 88 comboKeeper.openCombo(comboId); 89 }); 90 91 return this; 92 }, 93 94 openCombo: function(comboId) { 95 if (this.hasOwnProperty("combos") && this.combos.hasOwnProperty(comboId)) { 96 this.combos[comboId].options = {}; 97 if (this.combos[comboId].$modals.hasOwnProperty(0)) { 98 $(this.combos[comboId].$modals[0]).modal("show"); 99 } else { 100 this.addToCart(comboId); 101 } 102 } else { 103 throwError("Invalid combo ID specified."); 104 } 105 106 return this; 107 }, 108 109 setupAttestationModal: function ($modal, $nextModal = null) {
110 let $button = $modal.find(".modal-body button"); 111 if ($button.length === 0) { 112 $button = $modal.find("a.add-to-cart-button"); 113 } 114 if ($button.length > 0) { 115 if ($button.is("button")) { 116 $button.attr("type", "button"); 117 } 118 $button.removeAttr("data-ecommerce-action").addClass("btn-primary").removeClass("disabled"). 119 removeClass("btn-dark").removeAttr("disabled"); 120 if ($nextModal) { 121 $button.attr("data-toggle", "modal"); 122 $button.attr("data-target", "#" + $nextModal.attr("id")); 123 $button.on("click", function () { 124 $modal.off("hidden.bs.modal").on("hidden.bs.modal", function () { 125 $nextModal.modal("show"); 126 }).modal("hide"); 127 }); 128 } else { 129 $button.addClass("add-to-cart-button").on("click", function() { 130 comboKeeper.addToCart($modal.data("comboId"), $modal); 131 }); 132 } 133 } else { 134 throwError("Unable to find submit button for combo attestation modal"); 135 } 136 }, 137 138 setupModals: function(comboId) { 139 if (this.combos.hasOwnProperty(comboId) && this.combos[comboId].hasOwnProperty("$modals")) { 140 let $modals = this.combos[comboId].$modals; 141 142 $modals.each(function (index) { 143 let $modal = $(this); 144 $modal.data("comboId", comboId); 145 $modal.on("show.bs.modal", function () { 146 let $activeModal = $(this); 147 $activeModal.find(".success").hide(); 148 $activeModal.find("div.input.error").removeClass("error"); 149 $activeModal.find("input, select").val("").removeClass("form-error").removeClass("is-invalid"); 150 $activeModal.find("div.invalid-feedback").remove(); 151 }); 152 153 let $nextModal; 154 if ($modals.hasOwnProperty(index + 1)) { 155 $nextModal = $($modals[index + 1]); 156 } 157 158 if ($modal.hasClass("options-modal")) { 159 comboKeeper.setupOptionsModal($modal, $nextModal); 160 } else if ($modal.hasClass("attestation-modal")) { 161 comboKeeper.setupAttestationModal($modal, $nextModal); 162 } 163 }); 164 } 165 166 return this; 167 }, 168 169 setupOptionsModal: function($modal, $nextModal = null) { 170 let $button = $modal.find(".add-to-cart-button"); 171 if ($button.length > 0) { 172 if ($nextModal) { 173 $button.html("Submit"); 174 } 175 $button.removeAttr("data-ecommerce-action").addClass("btn-primary").removeClass("disabled"). 176 removeClass("btn-dark").removeAttr("disabled").html("Add to Cart"); 177 178 let productId = $button.attr("data-product-id"); 179 if (!productId) { 180 throw "Missing product ID on cart button"; 181 } 182 let priceId = $button.attr("data-price-id"); 183 if (!priceId) { 184 throw "Missing price ID on cart button"; 185 } 186 187 $button.on("click", function() { 188 let $formFields = $modal.find("select, input"); 189 let options = {}; 190 $formFields.each(function () { 191 let $field = $(this); 192 let optionId = $field.attr("name").match(/\[([A-Z0-9-]+)]/); 193 if (optionId.length === 2) { 194 optionId = optionId[1]; 195 options[optionId] = $field.val(); 196 } 197 }); 198 199 comboKeeper.validateProduct(productId, priceId, options, $modal, $nextModal); 200 }); 201 } else {
202 throwError("Unable to find submit button for combo modals"); 203 } 204 205 return this; 206 }, 207 208 validateProduct: function(productId, priceId, options, $modal, $nextModal = null) { 209 let success = false; 210 211 postData(API_ENDPOINT_ADD_TO_CART, { 212 product_id: productId, 213 quantity: 1, 214 price_id: priceId, 215 validate_only: 1, 216 options: options 217 }).then(response => { 218 if (response.hasOwnProperty("success") && response.success) { 219 let comboId = $modal.data("comboId"); 220 if (comboKeeper.combos.hasOwnProperty(comboId)) { 221 if (options) { 222 for (const property in options) { 223 comboKeeper.combos[comboId].options[property] = options[property]; 224 } 225 } 226 if ($nextModal) { 227 $modal.off("hidden.bs.modal").on("hidden.bs.modal", function() { 228 $nextModal.modal("show"); 229 }).modal("hide"); 230 } else { 231 comboKeeper.addToCart(comboId, $modal); 232 } 233 } 234 } else { 235 handleError(response, "combo"); 236 } 237 }); 238 239 return success; 240 } 241 }; 242 comboKeeper.init(); 243});
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.