class CartRemoveButton extends HTMLElement { constructor() { super(); this.addEventListener("click", (event) => { event.preventDefault(); const cartItems = this.closest("cart-items") || this.closest("cart-drawer-items"); cartItems.updateQuantity(this.dataset.index, 0); }); } } customElements.define("cart-remove-button", CartRemoveButton); class CartItems extends HTMLElement { constructor() { super(); this.lineItemStatusElement = document.getElementById("shopping-cart-line-item-status") || document.getElementById("CartDrawer-LineItemStatus"); const debouncedOnChange = debounce((event) => { this.onChange(event); }, ON_CHANGE_DEBOUNCE_TIMER); this.addEventListener("change", debouncedOnChange.bind(this)); } cartUpdateUnsubscriber = undefined; connectedCallback() { this.cartUpdateUnsubscriber = subscribe( PUB_SUB_EVENTS.cartUpdate, (event) => { if (event.source === "cart-items") { return; } this.onCartUpdate(); } ); } disconnectedCallback() { if (this.cartUpdateUnsubscriber) { this.cartUpdateUnsubscriber(); } } onChange(event) { this.updateQuantity( event.target.dataset.index, event.target.value, document.activeElement.getAttribute("name"), event.target.dataset.quantityVariantId ); } onCartUpdate() { if (this.tagName === "CART-DRAWER-ITEMS") { fetch(`${routes.cart_url}?section_id=cart-drawer`) .then((response) => response.text()) .then((responseText) => { const html = new DOMParser().parseFromString( responseText, "text/html" ); const selectors = ["cart-drawer-items", ".cart-drawer__footer"]; for (const selector of selectors) { const targetElement = document.querySelector(selector); const sourceElement = html.querySelector(selector); if (targetElement && sourceElement) { targetElement.replaceWith(sourceElement); } } }) .catch((e) => { console.error(e); }); } else { fetch(`${routes.cart_url}?section_id=main-cart-items`) .then((response) => response.text()) .then((responseText) => { const html = new DOMParser().parseFromString( responseText, "text/html" ); const sourceQty = html.querySelector("cart-items"); this.innerHTML = sourceQty.innerHTML; }) .catch((e) => { console.error(e); }); } } getSectionsToRender() { return [ { id: "main-cart-items", section: document.getElementById("main-cart-items").dataset.id, selector: ".js-contents", }, { id: "cart-icon-bubble", section: "cart-icon-bubble", selector: ".shopify-section", }, { id: "cart-live-region-text", section: "cart-live-region-text", selector: ".shopify-section", }, { id: "main-cart-footer", section: document.getElementById("main-cart-footer").dataset.id, selector: ".js-contents", }, ]; } updateQuantity(line, quantity, name, variantId) { this.enableLoading(line); const body = JSON.stringify({ line, quantity, sections: this.getSectionsToRender().map((section) => section.section), sections_url: window.location.pathname, }); fetch(`${routes.cart_change_url}`, { ...fetchConfig(), ...{ body } }) .then((response) => { return response.text(); }) .then((state) => { const parsedState = JSON.parse(state); const quantityElement = document.getElementById(`Quantity-${line}`) || document.getElementById(`Drawer-quantity-${line}`); const items = document.querySelectorAll(".cart-item"); if (parsedState.errors) { quantityElement.value = quantityElement.getAttribute("value"); this.updateLiveRegions(line, parsedState.errors); return; } this.classList.toggle("is-empty", parsedState.item_count === 0); const cartDrawerWrapper = document.querySelector("cart-drawer"); const cartFooter = document.getElementById("main-cart-footer"); if (cartFooter) cartFooter.classList.toggle("is-empty", parsedState.item_count === 0); if (cartDrawerWrapper) cartDrawerWrapper.classList.toggle( "is-empty", parsedState.item_count === 0 ); this.getSectionsToRender().forEach((section) => { const elementToReplace = document .getElementById(section.id) .querySelector(section.selector) || document.getElementById(section.id); elementToReplace.innerHTML = this.getSectionInnerHTML( parsedState.sections[section.section], section.selector ); }); const updatedValue = parsedState.items[line - 1] ? parsedState.items[line - 1].quantity : undefined; let message = ""; if ( items.length === parsedState.items.length && updatedValue !== parseInt(quantityElement.value) ) { if (typeof updatedValue === "undefined") { message = window.cartStrings.error; } else { message = window.cartStrings.quantityError.replace( "[quantity]", updatedValue ); } } this.updateLiveRegions(line, message); const lineItem = document.getElementById(`CartItem-${line}`) || document.getElementById(`CartDrawer-Item-${line}`); if (lineItem && lineItem.querySelector(`[name="${name}"]`)) { cartDrawerWrapper ? trapFocus( cartDrawerWrapper, lineItem.querySelector(`[name="${name}"]`) ) : lineItem.querySelector(`[name="${name}"]`).focus(); } else if (parsedState.item_count === 0 && cartDrawerWrapper) { trapFocus( cartDrawerWrapper.querySelector(".drawer__inner-empty"), cartDrawerWrapper.querySelector("a") ); } else if (document.querySelector(".cart-item") && cartDrawerWrapper) { trapFocus( cartDrawerWrapper, document.querySelector(".cart-item__name") ); } publish(PUB_SUB_EVENTS.cartUpdate, { source: "cart-items", cartData: parsedState, variantId: variantId, }); }) .catch(() => { this.querySelectorAll(".loading__spinner").forEach((overlay) => overlay.classList.add("hidden") ); const errors = document.getElementById("cart-errors") || document.getElementById("CartDrawer-CartErrors"); errors.textContent = window.cartStrings.error; }) .finally(() => { this.disableLoading(line); }); } updateLiveRegions(line, message) { const lineItemError = document.getElementById(`Line-item-error-${line}`) || document.getElementById(`CartDrawer-LineItemError-${line}`); if (lineItemError) lineItemError.querySelector(".cart-item__error-text").innerHTML = message; this.lineItemStatusElement.setAttribute("aria-hidden", true); const cartStatus = document.getElementById("cart-live-region-text") || document.getElementById("CartDrawer-LiveRegionText"); cartStatus.setAttribute("aria-hidden", false); setTimeout(() => { cartStatus.setAttribute("aria-hidden", true); }, 1000); } getSectionInnerHTML(html, selector) { return new DOMParser() .parseFromString(html, "text/html") .querySelector(selector).innerHTML; } enableLoading(line) { const mainCartItems = document.getElementById("main-cart-items") || document.getElementById("CartDrawer-CartItems"); mainCartItems.classList.add("cart__items--disabled"); const cartItemElements = this.querySelectorAll( `#CartItem-${line} .loading__spinner` ); const cartDrawerItemElements = this.querySelectorAll( `#CartDrawer-Item-${line} .loading__spinner` ); [...cartItemElements, ...cartDrawerItemElements].forEach((overlay) => overlay.classList.remove("hidden") ); document.activeElement.blur(); this.lineItemStatusElement.setAttribute("aria-hidden", false); } disableLoading(line) { const mainCartItems = document.getElementById("main-cart-items") || document.getElementById("CartDrawer-CartItems"); mainCartItems.classList.remove("cart__items--disabled"); const cartItemElements = this.querySelectorAll( `#CartItem-${line} .loading__spinner` ); const cartDrawerItemElements = this.querySelectorAll( `#CartDrawer-Item-${line} .loading__spinner` ); cartItemElements.forEach((overlay) => overlay.classList.add("hidden")); cartDrawerItemElements.forEach((overlay) => overlay.classList.add("hidden") ); } } customElements.define("cart-items", CartItems); if (!customElements.get("cart-note")) { customElements.define( "cart-note", class CartNote extends HTMLElement { constructor() { super(); this.addEventListener( "input", debounce((event) => { const body = JSON.stringify({ note: event.target.value }); fetch(`${routes.cart_update_url}`, { ...fetchConfig(), ...{ body }, }); }, ON_CHANGE_DEBOUNCE_TIMER) ); } } ); }