Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support Combined Listings and 2k Variants #3246

Merged
merged 2 commits into from
Mar 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions assets/base.css
Original file line number Diff line number Diff line change
Expand Up @@ -3240,6 +3240,7 @@ details-disclosure > details {
opacity: 1;
animation: none;
transition: none;
transform: none;
}

.scroll-trigger.scroll-trigger--design-mode.animate--slide-in {
Expand Down
5 changes: 5 additions & 0 deletions assets/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@ const PUB_SUB_EVENTS = {
quantityUpdate: 'quantity-update',
variantChange: 'variant-change',
cartError: 'cart-error',
sectionRefreshed: 'section-refreshed',
};

const SECTION_REFRESH_RESOURCE_TYPE = {
product: 'product',
};
549 changes: 322 additions & 227 deletions assets/global.js

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions assets/pickup-availability.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ if (!customElements.get('pickup-availability')) {
}

fetchAvailability(variantId) {
if (!variantId) return;

let rootUrl = this.dataset.rootUrl;
if (!rootUrl.endsWith('/')) {
rootUrl = rootUrl + '/';
Expand Down
2 changes: 2 additions & 0 deletions assets/quick-add.css
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
.quick-add-modal .scroll-trigger.scroll-trigger {
animation: none;
opacity: 1;
transform: none;
}

.quick-add-modal__content {
Expand Down Expand Up @@ -170,6 +171,7 @@ quick-add-modal .product__column-sticky {
}

quick-add-modal .product:not(.product--no-media) .product__info-wrapper {
padding-top: 2rem;
padding-left: 4rem;
max-width: 54%;
width: calc(54% - var(--grid-desktop-horizontal-spacing) / 2);
Expand Down
74 changes: 38 additions & 36 deletions assets/quick-add.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,83 +25,85 @@ if (!customElements.get('quick-add-modal')) {
.then((response) => response.text())
.then((responseText) => {
const responseHTML = new DOMParser().parseFromString(responseText, 'text/html');
this.productElement = responseHTML.querySelector('section[id^="MainProduct-"]');
this.productElement.classList.forEach((classApplied) => {
if (classApplied.startsWith('color-') || classApplied === 'gradient')
this.modalContent.classList.add(classApplied);
});
this.preventDuplicatedIDs();
this.removeDOMElements();
this.setInnerHTML(this.modalContent, this.productElement.innerHTML);
const productElement = responseHTML.querySelector('section[id^="MainProduct-"]');

this.preprocessHTML(productElement);
HTMLUpdateUtility.setInnerHTML(this.modalContent, productElement.innerHTML);

if (window.Shopify && Shopify.PaymentButton) {
Shopify.PaymentButton.init();
}

if (window.ProductModel) window.ProductModel.loadShopifyXR();

this.removeGalleryListSemantic();
this.updateImageSizes();
this.preventVariantURLSwitching();
super.show(opener);
})
.finally(() => {
this.bindProductChangeCallbacks();
opener.removeAttribute('aria-disabled');
opener.classList.remove('loading');
opener.querySelector('.loading__spinner').classList.add('hidden');
});
}

setInnerHTML(element, html) {
element.innerHTML = html;

// Reinjects the script tags to allow execution. By default, scripts are disabled when using element.innerHTML.
element.querySelectorAll('script').forEach((oldScriptTag) => {
const newScriptTag = document.createElement('script');
Array.from(oldScriptTag.attributes).forEach((attribute) => {
newScriptTag.setAttribute(attribute.name, attribute.value);
bindProductChangeCallbacks() {
const swapProductUtility = this.querySelector('variant-selects')?.swapProductUtility;
if (swapProductUtility) {
swapProductUtility.addPreProcessCallback(this.preprocessHTML.bind(this));
swapProductUtility.addPostProcessCallback(() => {
this.modalContent = this.querySelector('[id^="QuickAddInfo-"]');
this.bindProductChangeCallbacks();
});
newScriptTag.appendChild(document.createTextNode(oldScriptTag.innerHTML));
oldScriptTag.parentNode.replaceChild(newScriptTag, oldScriptTag);
}
}

preprocessHTML(productElement) {
productElement.classList.forEach((classApplied) => {
if (classApplied.startsWith('color-') || classApplied === 'gradient')
this.modalContent.classList.add(classApplied);
});
this.preventDuplicatedIDs(productElement);
this.removeDOMElements(productElement);
this.removeGalleryListSemantic(productElement);
this.updateImageSizes(productElement);
this.preventVariantURLSwitching(productElement);
}

preventVariantURLSwitching() {
const variantPicker = this.modalContent.querySelector('variant-selects');
preventVariantURLSwitching(productElement) {
const variantPicker = productElement.querySelector('variant-selects');
if (!variantPicker) return;

variantPicker.setAttribute('data-update-url', 'false');
}

removeDOMElements() {
const pickupAvailability = this.productElement.querySelector('pickup-availability');
removeDOMElements(productElement) {
const pickupAvailability = productElement.querySelector('pickup-availability');
if (pickupAvailability) pickupAvailability.remove();

const productModal = this.productElement.querySelector('product-modal');
const productModal = productElement.querySelector('product-modal');
if (productModal) productModal.remove();

const modalDialog = this.productElement.querySelectorAll('modal-dialog');
const modalDialog = productElement.querySelectorAll('modal-dialog');
if (modalDialog) modalDialog.forEach((modal) => modal.remove());
}

preventDuplicatedIDs() {
const sectionId = this.productElement.dataset.section;
this.productElement.innerHTML = this.productElement.innerHTML.replaceAll(sectionId, `quickadd-${sectionId}`);
this.productElement.querySelectorAll('variant-selects, product-info').forEach((element) => {
preventDuplicatedIDs(productElement) {
const sectionId = productElement.dataset.section;
productElement.innerHTML = productElement.innerHTML.replaceAll(sectionId, `quickadd-${sectionId}`);
productElement.querySelectorAll('variant-selects, product-info').forEach((element) => {
element.dataset.originalSection = sectionId;
});
}

removeGalleryListSemantic() {
const galleryList = this.modalContent.querySelector('[id^="Slider-Gallery"]');
removeGalleryListSemantic(productElement) {
const galleryList = productElement.querySelector('[id^="Slider-Gallery"]');
if (!galleryList) return;

galleryList.setAttribute('role', 'presentation');
galleryList.querySelectorAll('[id^="Slide-"]').forEach((li) => li.setAttribute('role', 'presentation'));
}

updateImageSizes() {
const product = this.modalContent.querySelector('.product');
updateImageSizes(productElement) {
const product = productElement.querySelector('.product');
const desktopColumns = product.classList.contains('product--columns');
if (!desktopColumns) return;

Expand Down
21 changes: 15 additions & 6 deletions assets/quick-order-list.js
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,6 @@ class QuickOrderListRemoveAllButton extends HTMLElement {

customElements.define('quick-order-list-remove-all-button', QuickOrderListRemoveAllButton);


class QuickOrderList extends HTMLElement {
constructor() {
super();
Expand Down Expand Up @@ -97,6 +96,7 @@ class QuickOrderList extends HTMLElement {
}

cartUpdateUnsubscriber = undefined;
sectionRefreshUnsubscriber = undefined;

onSubmit(event) {
event.preventDefault();
Expand All @@ -108,15 +108,24 @@ class QuickOrderList extends HTMLElement {
return;
}
// If its another section that made the update
this.onCartUpdate();
this.refresh();
});

this.sectionRefreshUnsubscriber = subscribe(PUB_SUB_EVENTS.sectionRefreshed, (event) => {
const isParentSectionUpdated =
this.sectionId && (event.data?.sectionId ?? '') === `${this.sectionId.split('__')[0]}__main`;

if (isParentSectionUpdated) {
this.refresh();
}
});

this.sectionId = this.dataset.id;
}

disconnectedCallback() {
if (this.cartUpdateUnsubscriber) {
this.cartUpdateUnsubscriber();
}
this.cartUpdateUnsubscriber?.();
this.sectionRefreshUnsubscriber?.();
}

defineInputsAndQuickOrderTable() {
Expand All @@ -140,7 +149,7 @@ class QuickOrderList extends HTMLElement {
}
}

onCartUpdate() {
refresh() {
fetch(`${window.location.pathname}?section_id=${this.sectionId}`)
.then((response) => response.text())
.then((responseText) => {
Expand Down
6 changes: 4 additions & 2 deletions sections/main-product.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -451,7 +451,7 @@
%}

{%- when 'variant_picker' -%}
{% render 'product-variant-picker', product: product, block: block, product_form_id: product_form_id %}

Check warning on line 454 in sections/main-product.liquid

View workflow job for this annotation

GitHub Actions / Theme Check Report

sections/main-product.liquid#L454

[NestedSnippet] Too many nested snippets

Check warning on line 454 in sections/main-product.liquid

View workflow job for this annotation

GitHub Actions / Theme Check Report

sections/main-product.liquid#L454

[NestedSnippet] Too many nested snippets

Check warning on line 454 in sections/main-product.liquid

View workflow job for this annotation

GitHub Actions / Theme Check Report

sections/main-product.liquid#L454

[NestedSnippet] Too many nested snippets
{%- when 'buy_buttons' -%}
{%- render 'buy-buttons',
block: block,
Expand Down Expand Up @@ -501,7 +501,9 @@
{%- when 'complementary' -%}
<product-recommendations
class="complementary-products quick-add-hidden{% if block.settings.make_collapsible_row %} is-accordion{% endif %}{% if block.settings.enable_quick_add %} complementary-products-contains-quick-add{% endif %}"
data-url="{{ routes.product_recommendations_url }}?section_id={{ section.id }}&product_id={{ product.id }}&limit={{ block.settings.product_list_limit }}&intent=complementary"
data-url="{{ routes.product_recommendations_url }}?limit={{ block.settings.product_list_limit }}&intent=complementary"
data-section-id="{{ section.id }}"
data-product-id="{{ product.id }}"
>
{%- if recommendations.performed and recommendations.products_count > 0 -%}
<aside
Expand Down Expand Up @@ -2273,4 +2275,4 @@
}
]
}
{% endschema %}
{% endschema %}
4 changes: 3 additions & 1 deletion sections/related-products.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,9 @@
<div class="color-{{ section.settings.color_scheme }} gradient">
<product-recommendations
class="related-products page-width section-{{ section.id }}-padding isolate{% if settings.animations_reveal_on_scroll %} scroll-trigger animate--slide-in{% endif %}"
data-url="{{ routes.product_recommendations_url }}?section_id={{ section.id }}&product_id={{ product.id }}&limit={{ section.settings.products_to_show }}"
data-url="{{ routes.product_recommendations_url }}?limit={{ section.settings.products_to_show }}"
data-section-id="{{ section.id }}"
data-product-id="{{ product.id }}"
>
{% if recommendations.performed and recommendations.products_count > 0 %}
<h2 class="related-products__heading inline-richtext {{ section.settings.heading_size }}">
Expand Down
10 changes: 8 additions & 2 deletions snippets/buy-buttons.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,10 @@
type="hidden"
name="id"
value="{{ product.selected_or_first_available_variant.id }}"
{% if product.selected_or_first_available_variant.available == false or quantity_rule_soldout %}
{% if product.selected_or_first_available_variant.available == false
or quantity_rule_soldout
or product.selected_or_first_available_variant == nil
%}
Copy link
Contributor Author

@lhoffbeck lhoffbeck Feb 27, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

product.selected_or_first_available_variant may be nil if the section is rendered via the section api with an option_values param. This occurs when the list of option value IDs passed via option_values does not map to a variant.

In this case, we want the buy buttons to be disabled by default.

disabled
{% endif %}
class="product-variant-id"
Expand All @@ -80,7 +83,10 @@
type="submit"
name="add"
class="product-form__submit button button--full-width {% if show_dynamic_checkout %}button--secondary{% else %}button--primary{% endif %}"
{% if product.selected_or_first_available_variant.available == false or quantity_rule_soldout %}
{% if product.selected_or_first_available_variant.available == false
or quantity_rule_soldout
or product.selected_or_first_available_variant == nil
%}
disabled
{% endif %}
>
Expand Down
2 changes: 2 additions & 0 deletions snippets/price.liquid
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@
endif
-%}

{%- unless target == nil -%}
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is another guard against nil variants, see above. If the variant is nil, we don't render a price.

<div
class="
price
Expand Down Expand Up @@ -126,3 +127,4 @@
</span>
{%- endif -%}
</div>
{% endunless %}
Loading
Loading