Diff
checker
Text
Text
Images
Documents
Excel
Folders
Legal
Enterprise
Desktop
Pricing
Sign in
Download Diffchecker Desktop
Compare text
Find the difference between two text files
Tools
History
Real-time editor
Hide whitespace changes
Hide unchanged lines
Disable line wrap
Layout
Split
Unified
Diff precision
Smart
Word
Char
Text styles
Change appearance
Syntax highlighting
Choose syntax
Ignore
Transform text
Go to first change
Edit input
Diffchecker Desktop
The most secure way to run Diffchecker. Get the Diffchecker Desktop app: your diffs never leave your computer!
Get Desktop
cart.js-default-vs-modified
Created
5 months ago
Diff never expires
Clear
Export
Share
Explain
83 removals
Lines
Total
Removed
Characters
Total
Removed
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
297 lines
Copy
89 additions
Lines
Total
Added
Characters
Total
Added
To continue using this feature, upgrade to
Diff
checker
Pro
View Pricing
314 lines
Copy
class CartRemoveButton extends HTMLElement {
class CartRemoveButton extends HTMLElement {
constructor() {
constructor() {
super();
super();
this.addEventListener('click', (event) => {
this.addEventListener('click', (event) => {
event.preventDefault();
event.preventDefault();
const cartItems = this.closest('cart-items') || this.closest('cart-drawer-items');
const cartItems = this.closest('cart-items') || this.closest('cart-drawer-items');
cartItems.updateQuantity(this.dataset.index, 0, event);
cartItems.updateQuantity(this.dataset.index, 0, event);
});
});
}
}
}
}
customElements.define('cart-remove-button', CartRemoveButton);
customElements.define('cart-remove-button', CartRemoveButton);
class CartItems extends HTMLElement {
class CartItems extends HTMLElement {
constructor() {
constructor() {
super();
super();
this.lineItemStatusElement =
this.lineItemStatusElement =
document.getElementById('shopping-cart-line-item-status') || document.getElementById('CartDrawer-LineItemStatus');
document.getElementById('shopping-cart-line-item-status') || document.getElementById('CartDrawer-LineItemStatus');
const debouncedOnChange = debounce((event) => {
const debouncedOnChange = debounce((event) => {
this.onChange(event);
this.onChange(event);
}, ON_CHANGE_DEBOUNCE_TIMER);
}, ON_CHANGE_DEBOUNCE_TIMER);
this.addEventListener('change', debouncedOnChange.bind(this));
this.addEventListener('change', debouncedOnChange.bind(this));
}
}
cartUpdateUnsubscriber = undefined;
cartUpdateUnsubscriber = undefined;
connectedCallback() {
connectedCallback() {
this.cartUpdateUnsubscriber = subscribe(PUB_SUB_EVENTS.cartUpdate, (event) => {
this.cartUpdateUnsubscriber = subscribe(PUB_SUB_EVENTS.cartUpdate, (event) => {
if (event.source === 'cart-items') {
if (event.source === 'cart-items') {
return;
return;
}
}
return this.onCartUpdate();
return this.onCartUpdate();
});
});
}
}
disconnectedCallback() {
disconnectedCallback() {
if (this.cartUpdateUnsubscriber) {
if (this.cartUpdateUnsubscriber) {
this.cartUpdateUnsubscriber();
this.cartUpdateUnsubscriber();
}
}
}
}
resetQuantityInput(id) {
resetQuantityInput(id) {
const input = this.querySelector(`#Quantity-${id}`);
const input = this.querySelector(`#Quantity-${id}`);
input.value = input.getAttribute('value');
input.value = input.getAttribute('value');
this.isEnterPressed = false;
this.isEnterPressed = false;
}
}
setValidity(event, index, message) {
setValidity(event, index, message) {
event.target.setCustomValidity(message);
event.target.setCustomValidity(message);
event.target.reportValidity();
event.target.reportValidity();
this.resetQuantityInput(index);
this.resetQuantityInput(index);
event.target.select();
event.target.select();
}
}
validateQuantity(event) {
validateQuantity(event) {
const inputValue = parseInt(event.target.value);
const inputValue = parseInt(event.target.value);
const index = event.target.dataset.index;
const index = event.target.dataset.index;
let message = '';
let message = '';
if (inputValue < event.target.dataset.min) {
if (inputValue < event.target.dataset.min) {
message = window.quickOrderListStrings.min_error.replace('[min]', event.target.dataset.min);
message = window.quickOrderListStrings.min_error.replace('[min]', event.target.dataset.min);
} else if (inputValue > parseInt(event.target.max)) {
} else if (inputValue > parseInt(event.target.max)) {
message = window.quickOrderListStrings.max_error.replace('[max]', event.target.max);
message = window.quickOrderListStrings.max_error.replace('[max]', event.target.max);
} else if (inputValue % parseInt(event.target.step) !== 0) {
} else if (inputValue % parseInt(event.target.step) !== 0) {
message = window.quickOrderListStrings.step_error.replace('[step]', event.target.step);
message = window.quickOrderListStrings.step_error.replace('[step]', event.target.step);
}
}
if (message) {
if (message) {
this.setValidity(event, index, message);
this.setValidity(event, index, message);
} else {
} else {
event.target.setCustomValidity('');
event.target.setCustomValidity('');
event.target.reportValidity();
event.target.reportValidity();
this.updateQuantity(
this.updateQuantity(
index,
index,
inputValue,
inputValue,
event,
event,
document.activeElement.getAttribute('name'),
document.activeElement.getAttribute('name'),
event.target.dataset.quantityVariantId
event.target.dataset.quantityVariantId
);
);
}
}
}
}
onChange(event) {
onChange(event) {
this.validateQuantity(event);
this.validateQuantity(event);
}
}
onCartUpdate() {
onCartUpdate() {
if (this.tagName === 'CART-DRAWER-ITEMS') {
if (this.tagName === 'CART-DRAWER-ITEMS') {
return fetch(`${routes.cart_url}?section_id=cart-drawer`)
return fetch(`${routes.cart_url}?section_id=cart-drawer`)
.then((response) => response.text())
.then((response) => response.text())
.then((responseText) => {
.then((responseText) => {
const html = new DOMParser().parseFromString(responseText, 'text/html');
const html = new DOMParser().parseFromString(responseText, 'text/html');
const selectors = ['cart-drawer-items', '.cart-drawer__footer'];
const selectors = ['cart-drawer-items', '.cart-drawer__footer'];
for (const selector of selectors) {
for (const selector of selectors) {
const targetElement = document.querySelector(selector);
const targetElement = document.querySelector(selector);
const sourceElement = html.querySelector(selector);
const sourceElement = html.querySelector(selector);
if (targetElement && sourceElement) {
if (targetElement && sourceElement) {
targetElement.replaceWith(sourceElement);
targetElement.replaceWith(sourceElement);
}
}
}
}
})
})
.catch((e) => {
.catch((e) => {
console.error(e);
console.error(e);
});
});
} else {
} else {
return fetch(`${routes.cart_url}?section_id=main-cart-items`)
return fetch(`${routes.cart_url}?section_id=main-cart-items`)
.then((response) => response.text())
.then((response) => response.text())
.then((responseText) => {
.then((responseText) => {
const html = new DOMParser().parseFromString(responseText, 'text/html');
const html = new DOMParser().parseFromString(responseText, 'text/html');
const sourceQty = html.querySelector('cart-items');
const sourceQty = html.querySelector('cart-items');
this.innerHTML = sourceQty.innerHTML;
this.innerHTML = sourceQty.innerHTML;
})
})
.catch((e) => {
.catch((e) => {
console.error(e);
console.error(e);
});
});
}
}
}
}
getSectionsToRender() {
getSectionsToRender() {
return [
return [
{
{
id: 'main-cart-items',
id: 'main-cart-items',
section: document.getElementById('main-cart-items').dataset.id,
section: document.getElementById('main-cart-items').dataset.id,
selector: '.js-contents',
selector: '.js-contents',
},
},
{
{
id: 'cart-icon-bubble',
id: 'cart-icon-bubble',
section: 'cart-icon-bubble',
section: 'cart-icon-bubble',
Copy
Copied
Copy
Copied
selector: '.
shopify-section
',
selector: '.
cart-count-bubble
',
},
},
{
{
id: 'cart-live-region-text',
id: 'cart-live-region-text',
section: 'cart-live-region-text',
section: 'cart-live-region-text',
selector: '.shopify-section',
selector: '.shopify-section',
},
},
{
{
id: 'main-cart-footer',
id: 'main-cart-footer',
section: document.getElementById('main-cart-footer').dataset.id,
section: document.getElementById('main-cart-footer').dataset.id,
selector: '.js-contents',
selector: '.js-contents',
},
},
];
];
}
}
Copy
Copied
Copy
Copied
updateQuantity(line, quantity, event, name, variantId) {
updateQuantity(line, quantity, event, name, variantId) {
const eventTarget = event.currentTarget instanceof CartRemoveButton ? 'clear' : 'change';
const eventTarget = event.currentTarget instanceof CartRemoveButton ? 'clear' : 'change';
const cartPerformanceUpdateMarker = CartPerformance.createStartingMarker(`${eventTarget}:user-action`);
const cartPerformanceUpdateMarker = CartPerformance.createStartingMarker(`${eventTarget}:user-action`);
Copy
Copied
Copy
Copied
this.enableLoading(line);
this.enableLoading(line);
Copy
Copied
Copy
Copied
const body = JSON.stringify({
// Optimistic UI update
line,
const quantityElement =
quantity,
document.getElementById(`Quantity-${line}`) || document.getElementById(`Drawer-quantity-${line}`);
sections: this.getSectionsToRender().map((section) => section.section),
if (quantityElement) quantityElement.value = quantity;
sections_url: window.location.pathname,
});
Copy
Copied
Copy
Copied
fetch(`${routes.cart_change_url}`, { ...fetchConfig(), ...{
body
} })
const
body
= JSON.stringify(
{
.then((response) =>
{
line,
return response.text();
quantity,
})
sections: this.getSectionsToRender().map((section
) =>
section.section),
.then((state
) =>
{
sections_url: window.location.pathname,
const parsedState = JSON.parse(state
);
}
);
Copy
Copied
Copy
Copied
CartPerformance.measure
(`${
eventTarget}:paint-updated-sections`, (
) => {
fetch
(`${
routes.cart_change_url}`, { ...fetchConfig(), body })
const
quantityElement =
.then((response) => response.text())
document.getElementById(`Quantity-${line}`) || document.getElementById(`Drawer-quantity-${line}`);
.then((state
) => {
const items = document.querySelectorAll('.cart-item'
);
const
parsedState = JSON.parse(state
);
Copy
Copied
Copy
Copied
if (parsedState.errors) {
CartPerformance.measure(`${eventTarget}:paint-updated-sections`, () => {
quantityElement.value = quantityElement.getAttribute('value');
// Handle errors
this.updateLiveRegions(line, parsedState.errors);
if (parsedState.errors) {
return;
if (quantityElement)
quantityElement.value = quantityElement.getAttribute('value');
}
this.updateLiveRegions(line, parsedState.errors);
return;
}
Copy
Copied
Copy
Copied
this.classList.toggle('is-
empty
', parsedState.item_count === 0);
// Update
empty
state classes
const cartDrawerWrapper = document.querySelector('cart-drawer');
const cartDrawerWrapper = document.querySelector('cart-drawer');
const cartFooter = document.getElementById('main-cart-footer');
const cartFooter = document.getElementById('main-cart-footer');
const isEmpty = parsedState.item_count === 0;
Copy
Copied
Copy
Copied
if (cartFooter) cartFooter.classList.toggle('is-empty',
parsedState.item_count === 0
);
this.classList.toggle('is-empty', isEmpty);
if (cartDrawerWrapper) cartDrawerWrapper.classList.toggle('is-empty',
parsedState.item_count === 0
);
if (cartFooter) cartFooter.classList.toggle('is-empty',
isEmpty
);
if (cartDrawerWrapper) cartDrawerWrapper.classList.toggle('is-empty',
isEmpty
);
Copy
Copied
Copy
Copied
this.getSectionsToRender().forEach((section) => {
// Update only existing sections
const elementToReplace =
this.getSectionsToRender().forEach((section) => {
document.
getElementById(section.id).
querySelector(section.selector) ||
const sectionHTML = parsedState.sections?.[section.section];
document.getElementById(section.id);
if (!sectionHTML) return;
elementToReplace.innerHTML = this.getSectionInnerHTML(
parsedState.sections[section.
section
],
const elementToReplace =
section.selector
document.
querySelector(section.selector) ||
document.getElementById(section.id);
);
if (!elementToReplace) return;
}
);
const updatedValue = parsedState.items[line - 1]
? parsedState.items[line - 1]
.quantity
: undefined;
elementToReplace.innerHTML = this.getSectionInnerHTML(
section
HTML,
section.selector
);
let message = '';
});
if (items.length === parsedState.items.length && updatedValue !== parseInt(quantityElement.value)) {
if (typeof
updatedValue ===
'
undefined
') {
// Update quantity messages
message =
window.cartStrings.error
;
const items = document.querySelectorAll('.cart-item'
);
} else {
const updatedValue = parsedState.items[line - 1]
?
.quantity
;
message =
window.cartStrings.quantityError.replace('[quantity]', updatedValue);
let message = '';
}
}
if (items.length === parsedState.items.length && updatedValue !== parseInt(quantityElement.value)) {
this.updateLiveRegions(line, message);
message =
updatedValue ===
undefined
?
window.cartStrings.error
:
window.cartStrings.quantityError.replace('[quantity]', updatedValue);
}
this.updateLiveRegions(line, message);
Copy
Copied
Copy
Copied
// Focus trapping after DOM paints
requestAnimationFrame(() => {
const lineItem =
const lineItem =
document.getElementById(`CartItem-${line}`) || document.getElementById(`CartDrawer-Item-${line}`);
document.getElementById(`CartItem-${line}`) || document.getElementById(`CartDrawer-Item-${line}`);
Copy
Copied
Copy
Copied
if (lineItem
&& lineItem
.querySelector(`[name="${name}"]`)
) {
cartDrawerWrapper
if (lineItem
?
.querySelector(`[name="${name}"]`)
&&
cartDrawerWrapper
) {
?
trapFocus(cartDrawerWrapper, lineItem.querySelector(`[name="${name}"]`))
trapFocus(cartDrawerWrapper, lineItem.querySelector(`[name="${name}"]`))
;
: lineItem.querySelector(`[name="${name}"]`).focus()
;
} else if (
isEmpty
&& cartDrawerWrapper) {
} else if (
parsedState.item_count === 0
&& cartDrawerWrapper) {
const emptyFocus = cartDrawerWrapper.querySelector('.drawer__inner-empty a');
trapFocus(cartDrawerWrapper.querySelector('.drawer__inner-empty'),
cartDrawerWrapper.querySelector('a')
);
if (emptyFocus)
trapFocus(cartDrawerWrapper.querySelector('.drawer__inner-empty'),
emptyFocus
);
} else if (document.querySelector('.cart-item') && cartDrawerWrapper) {
} else if (document.querySelector('.cart-item') && cartDrawerWrapper) {
trapFocus(cartDrawerWrapper, document.querySelector('.cart-item__name'));
trapFocus(cartDrawerWrapper, document.querySelector('.cart-item__name'));
Copy
Copied
Copy
Copied
} else if (lineItem?.querySelector(`[name="${name}"]`)) {
lineItem.querySelector(`[name="${name}"]`).focus();
}
}
});
});
Copy
Copied
Copy
Copied
});
Copy
Copied
Copy
Copied
publish(PUB_SUB_EVENTS.cartUpdate, {
source: 'cart-items',
cartData: parsedState,
variantId: variantId
});
publish(PUB_SUB_EVENTS.cartUpdate, {
})
source: 'cart-items',
.catch(() => {
cartData: parsedState,
this.querySelectorAll('.loading__spinner').forEach((overlay) => overlay.classList.add('hidden'));
variantId: variantId
,
const errors = document.getElementById('cart-errors') || document.getElementById('CartDrawer-CartErrors');
errors.textContent = window.cartStrings.error;
})
.finally(() => {
this.disableLoading(line);
CartPerformance.measureFromMarker(`${eventTarget}:user-action`, cartPerformanceUpdateMarker);
});
});
Copy
Copied
Copy
Copied
}
})
.catch(() => {
this.querySelectorAll('.loading__spinner').forEach((overlay) => overlay.classList.add('hidden'));
const errors = document.getElementById('cart-errors') || document.getElementById('CartDrawer-CartErrors');
if (errors) errors.textContent = window.cartStrings.error;
})
.finally(() => {
this.disableLoading(line);
CartPerformance.measureFromMarker(`${eventTarget}:user-action`, cartPerformanceUpdateMarker);
});
}
updateLiveRegions(line, message) {
updateLiveRegions(line, message) {
const lineItemError =
const lineItemError =
document.getElementById(`Line-item-error-${line}`) || document.getElementById(`CartDrawer-LineItemError-${line}`);
document.getElementById(`Line-item-error-${line}`) || document.getElementById(`CartDrawer-LineItemError-${line}`);
if (lineItemError) lineItemError.querySelector('.cart-item__error-text').textContent = message;
if (lineItemError) lineItemError.querySelector('.cart-item__error-text').textContent = message;
this.lineItemStatusElement.setAttribute('aria-hidden', true);
this.lineItemStatusElement.setAttribute('aria-hidden', true);
const cartStatus =
const cartStatus =
document.getElementById('cart-live-region-text') || document.getElementById('CartDrawer-LiveRegionText');
document.getElementById('cart-live-region-text') || document.getElementById('CartDrawer-LiveRegionText');
cartStatus.setAttribute('aria-hidden', false);
cartStatus.setAttribute('aria-hidden', false);
setTimeout(() => {
setTimeout(() => {
cartStatus.setAttribute('aria-hidden', true);
cartStatus.setAttribute('aria-hidden', true);
}, 1000);
}, 1000);
}
}
getSectionInnerHTML(html, selector) {
getSectionInnerHTML(html, selector) {
return new DOMParser().parseFromString(html, 'text/html').querySelector(selector).innerHTML;
return new DOMParser().parseFromString(html, 'text/html').querySelector(selector).innerHTML;
}
}
enableLoading(line) {
enableLoading(line) {
const mainCartItems = document.getElementById('main-cart-items') || document.getElementById('CartDrawer-CartItems');
const mainCartItems = document.getElementById('main-cart-items') || document.getElementById('CartDrawer-CartItems');
mainCartItems.classList.add('cart__items--disabled');
mainCartItems.classList.add('cart__items--disabled');
const cartItemElements = this.querySelectorAll(`#CartItem-${line} .loading__spinner`);
const cartItemElements = this.querySelectorAll(`#CartItem-${line} .loading__spinner`);
const cartDrawerItemElements = this.querySelectorAll(`#CartDrawer-Item-${line} .loading__spinner`);
const cartDrawerItemElements = this.querySelectorAll(`#CartDrawer-Item-${line} .loading__spinner`);
[...cartItemElements, ...cartDrawerItemElements].forEach((overlay) => overlay.classList.remove('hidden'));
[...cartItemElements, ...cartDrawerItemElements].forEach((overlay) => overlay.classList.remove('hidden'));
document.activeElement.blur();
document.activeElement.blur();
this.lineItemStatusElement.setAttribute('aria-hidden', false);
this.lineItemStatusElement.setAttribute('aria-hidden', false);
}
}
disableLoading(line) {
disableLoading(line) {
const mainCartItems = document.getElementById('main-cart-items') || document.getElementById('CartDrawer-CartItems');
const mainCartItems = document.getElementById('main-cart-items') || document.getElementById('CartDrawer-CartItems');
mainCartItems.classList.remove('cart__items--disabled');
mainCartItems.classList.remove('cart__items--disabled');
const cartItemElements = this.querySelectorAll(`#CartItem-${line} .loading__spinner`);
const cartItemElements = this.querySelectorAll(`#CartItem-${line} .loading__spinner`);
const cartDrawerItemElements = this.querySelectorAll(`#CartDrawer-Item-${line} .loading__spinner`);
const cartDrawerItemElements = this.querySelectorAll(`#CartDrawer-Item-${line} .loading__spinner`);
cartItemElements.forEach((overlay) => overlay.classList.add('hidden'));
cartItemElements.forEach((overlay) => overlay.classList.add('hidden'));
cartDrawerItemElements.forEach((overlay) => overlay.classList.add('hidden'));
cartDrawerItemElements.forEach((overlay) => overlay.classList.add('hidden'));
}
}
}
}
customElements.define('cart-items', CartItems);
customElements.define('cart-items', CartItems);
if (!customElements.get('cart-note')) {
if (!customElements.get('cart-note')) {
customElements.define(
customElements.define(
'cart-note',
'cart-note',
class CartNote extends HTMLElement {
class CartNote extends HTMLElement {
constructor() {
constructor() {
super();
super();
this.addEventListener(
this.addEventListener(
'input',
'input',
debounce((event) => {
debounce((event) => {
const body = JSON.stringify({ note: event.target.value });
const body = JSON.stringify({ note: event.target.value });
fetch(`${routes.cart_update_url}`, { ...fetchConfig(), ...{ body } }).then(() =>
fetch(`${routes.cart_update_url}`, { ...fetchConfig(), ...{ body } }).then(() =>
CartPerformance.measureFromEvent('note-update:user-action', event)
CartPerformance.measureFromEvent('note-update:user-action', event)
);
);
}, ON_CHANGE_DEBOUNCE_TIMER)
}, ON_CHANGE_DEBOUNCE_TIMER)
);
);
}
}
}
}
);
);
}
}
Copy
Copied
Copy
Copied
Saved diffs
Original text
Open file
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, event); }); } } 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; } return this.onCartUpdate(); }); } disconnectedCallback() { if (this.cartUpdateUnsubscriber) { this.cartUpdateUnsubscriber(); } } resetQuantityInput(id) { const input = this.querySelector(`#Quantity-${id}`); input.value = input.getAttribute('value'); this.isEnterPressed = false; } setValidity(event, index, message) { event.target.setCustomValidity(message); event.target.reportValidity(); this.resetQuantityInput(index); event.target.select(); } validateQuantity(event) { const inputValue = parseInt(event.target.value); const index = event.target.dataset.index; let message = ''; if (inputValue < event.target.dataset.min) { message = window.quickOrderListStrings.min_error.replace('[min]', event.target.dataset.min); } else if (inputValue > parseInt(event.target.max)) { message = window.quickOrderListStrings.max_error.replace('[max]', event.target.max); } else if (inputValue % parseInt(event.target.step) !== 0) { message = window.quickOrderListStrings.step_error.replace('[step]', event.target.step); } if (message) { this.setValidity(event, index, message); } else { event.target.setCustomValidity(''); event.target.reportValidity(); this.updateQuantity( index, inputValue, event, document.activeElement.getAttribute('name'), event.target.dataset.quantityVariantId ); } } onChange(event) { this.validateQuantity(event); } onCartUpdate() { if (this.tagName === 'CART-DRAWER-ITEMS') { return 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 { return 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, event, name, variantId) { const eventTarget = event.currentTarget instanceof CartRemoveButton ? 'clear' : 'change'; const cartPerformanceUpdateMarker = CartPerformance.createStartingMarker(`${eventTarget}:user-action`); 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); CartPerformance.measure(`${eventTarget}:paint-updated-sections`, () => { 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); CartPerformance.measureFromMarker(`${eventTarget}:user-action`, cartPerformanceUpdateMarker); }); } updateLiveRegions(line, message) { const lineItemError = document.getElementById(`Line-item-error-${line}`) || document.getElementById(`CartDrawer-LineItemError-${line}`); if (lineItemError) lineItemError.querySelector('.cart-item__error-text').textContent = 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 } }).then(() => CartPerformance.measureFromEvent('note-update:user-action', event) ); }, ON_CHANGE_DEBOUNCE_TIMER) ); } } ); }
Changed text
Open file
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, event); }); } } 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; } return this.onCartUpdate(); }); } disconnectedCallback() { if (this.cartUpdateUnsubscriber) { this.cartUpdateUnsubscriber(); } } resetQuantityInput(id) { const input = this.querySelector(`#Quantity-${id}`); input.value = input.getAttribute('value'); this.isEnterPressed = false; } setValidity(event, index, message) { event.target.setCustomValidity(message); event.target.reportValidity(); this.resetQuantityInput(index); event.target.select(); } validateQuantity(event) { const inputValue = parseInt(event.target.value); const index = event.target.dataset.index; let message = ''; if (inputValue < event.target.dataset.min) { message = window.quickOrderListStrings.min_error.replace('[min]', event.target.dataset.min); } else if (inputValue > parseInt(event.target.max)) { message = window.quickOrderListStrings.max_error.replace('[max]', event.target.max); } else if (inputValue % parseInt(event.target.step) !== 0) { message = window.quickOrderListStrings.step_error.replace('[step]', event.target.step); } if (message) { this.setValidity(event, index, message); } else { event.target.setCustomValidity(''); event.target.reportValidity(); this.updateQuantity( index, inputValue, event, document.activeElement.getAttribute('name'), event.target.dataset.quantityVariantId ); } } onChange(event) { this.validateQuantity(event); } onCartUpdate() { if (this.tagName === 'CART-DRAWER-ITEMS') { return 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 { return 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: '.cart-count-bubble', }, { 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, event, name, variantId) { const eventTarget = event.currentTarget instanceof CartRemoveButton ? 'clear' : 'change'; const cartPerformanceUpdateMarker = CartPerformance.createStartingMarker(`${eventTarget}:user-action`); this.enableLoading(line); // Optimistic UI update const quantityElement = document.getElementById(`Quantity-${line}`) || document.getElementById(`Drawer-quantity-${line}`); if (quantityElement) quantityElement.value = quantity; 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) => response.text()) .then((state) => { const parsedState = JSON.parse(state); CartPerformance.measure(`${eventTarget}:paint-updated-sections`, () => { // Handle errors if (parsedState.errors) { if (quantityElement) quantityElement.value = quantityElement.getAttribute('value'); this.updateLiveRegions(line, parsedState.errors); return; } // Update empty state classes const cartDrawerWrapper = document.querySelector('cart-drawer'); const cartFooter = document.getElementById('main-cart-footer'); const isEmpty = parsedState.item_count === 0; this.classList.toggle('is-empty', isEmpty); if (cartFooter) cartFooter.classList.toggle('is-empty', isEmpty); if (cartDrawerWrapper) cartDrawerWrapper.classList.toggle('is-empty', isEmpty); // Update only existing sections this.getSectionsToRender().forEach((section) => { const sectionHTML = parsedState.sections?.[section.section]; if (!sectionHTML) return; const elementToReplace = document.querySelector(section.selector) || document.getElementById(section.id); if (!elementToReplace) return; elementToReplace.innerHTML = this.getSectionInnerHTML(sectionHTML, section.selector); }); // Update quantity messages const items = document.querySelectorAll('.cart-item'); const updatedValue = parsedState.items[line - 1]?.quantity; let message = ''; if (items.length === parsedState.items.length && updatedValue !== parseInt(quantityElement.value)) { message = updatedValue === undefined ? window.cartStrings.error : window.cartStrings.quantityError.replace('[quantity]', updatedValue); } this.updateLiveRegions(line, message); // Focus trapping after DOM paints requestAnimationFrame(() => { const lineItem = document.getElementById(`CartItem-${line}`) || document.getElementById(`CartDrawer-Item-${line}`); if (lineItem?.querySelector(`[name="${name}"]`) && cartDrawerWrapper) { trapFocus(cartDrawerWrapper, lineItem.querySelector(`[name="${name}"]`)); } else if (isEmpty && cartDrawerWrapper) { const emptyFocus = cartDrawerWrapper.querySelector('.drawer__inner-empty a'); if (emptyFocus) trapFocus(cartDrawerWrapper.querySelector('.drawer__inner-empty'), emptyFocus); } else if (document.querySelector('.cart-item') && cartDrawerWrapper) { trapFocus(cartDrawerWrapper, document.querySelector('.cart-item__name')); } else if (lineItem?.querySelector(`[name="${name}"]`)) { lineItem.querySelector(`[name="${name}"]`).focus(); } }); }); 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'); if (errors) errors.textContent = window.cartStrings.error; }) .finally(() => { this.disableLoading(line); CartPerformance.measureFromMarker(`${eventTarget}:user-action`, cartPerformanceUpdateMarker); }); } updateLiveRegions(line, message) { const lineItemError = document.getElementById(`Line-item-error-${line}`) || document.getElementById(`CartDrawer-LineItemError-${line}`); if (lineItemError) lineItemError.querySelector('.cart-item__error-text').textContent = 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 } }).then(() => CartPerformance.measureFromEvent('note-update:user-action', event) ); }, ON_CHANGE_DEBOUNCE_TIMER) ); } } ); }
Find difference