Diff
checker
Texte
Texte
Images
Documents
Excel
Dossiers
Legal
Enterprise
Application de bureau
Prix
Se connecter
Télécharger Diffchecker Desktop
Comparer le texte
Trouver la différence entre deux fichiers texte
Outils
Historique
Éditeur live
Masquer les espaces
Cacher identiques
Sans retour à la ligne
Vue
Divisé
Unifié
Niveau de précision
Intelligent
Mot
Caractère
Styles de texte
Modifier l’apparence
Coloration syntaxique
Choisir la syntaxe
Ignorer
Transformer le texte
Aller au premier écart
Modifier l'entrée
Diffchecker Desktop
La façon la plus sécurisée d'utiliser Diffchecker. Obtenez l'application Diffchecker Desktop : vos diffs ne quittent jamais votre ordinateur !
Obtenir Desktop
cart.js-default-vs-modified
Créé
il y a 5 mois
Le diff n'expire jamais
Effacer
Exporter
Partager
Expliquer
83 suppressions
Lignes
Total
Supprimé
Caractères
Total
Supprimé
Pour continuer à utiliser cette fonctionnalité, passez à
Diff
checker
Pro
Voir les prix
297 lignes
Copier tout
89 ajouts
Lignes
Total
Ajouté
Caractères
Total
Ajouté
Pour continuer à utiliser cette fonctionnalité, passez à
Diff
checker
Pro
Voir les prix
314 lignes
Copier tout
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',
Copier
Copié
Copier
Copié
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',
},
},
];
];
}
}
Copier
Copié
Copier
Copié
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`);
Copier
Copié
Copier
Copié
this.enableLoading(line);
this.enableLoading(line);
Copier
Copié
Copier
Copié
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,
});
Copier
Copié
Copier
Copié
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
);
}
);
Copier
Copié
Copier
Copié
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
);
Copier
Copié
Copier
Copié
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;
}
Copier
Copié
Copier
Copié
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;
Copier
Copié
Copier
Copié
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
);
Copier
Copié
Copier
Copié
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);
Copier
Copié
Copier
Copié
// 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}`);
Copier
Copié
Copier
Copié
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'));
Copier
Copié
Copier
Copié
} else if (lineItem?.querySelector(`[name="${name}"]`)) {
lineItem.querySelector(`[name="${name}"]`).focus();
}
}
});
});
Copier
Copié
Copier
Copié
});
Copier
Copié
Copier
Copié
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);
});
});
Copier
Copié
Copier
Copié
}
})
.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)
);
);
}
}
}
}
);
);
}
}
Copier
Copié
Copier
Copié
Différences enregistrées
Texte d'origine
Ouvrir un fichier
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) ); } } ); }
Texte modifié
Ouvrir un fichier
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) ); } } ); }
Trouver la différence