From 0a4e0160d072cfef3fae34416f7c12245276102a Mon Sep 17 00:00:00 2001 From: Dan Menard Date: Fri, 5 Jul 2024 11:40:07 -0400 Subject: [PATCH] v15 fixes (#3547) * [Product] Zoom on hover fix on variant change (#3511) * Zoom on hover fix on variant change * add conditional * Add early return in updateQuantityRules function if no quantity selector is present (#3515) * Fix bug where request url contains duplicated params when switching before the prior response is returned (#3521) * Fixes bug where image flashes when switching to variant with the same featured image; fixes bug where variant without featured image would fallback to the product image (#3516) Fix issue with thumbnail not updating * Fixed bug when reading selected option values. Removed unused script tag containing variant json. (#3520) * escape titles that weren't (#3514) * Support multiple product templates for the same combined listing (#3526) * Updated quick order list to rely on the variant title field (#3528) * Release15fix (#3531) * Revert "Update from Shopify for theme dawn/release/15.0.0" This reverts commit 5b20d897767f48370d6fba9ecefa5aeb97a6902b. * Revert "Update from Shopify for theme dawn/release/15.0.0" This reverts commit f0b822dbeaa934ecbb6f02704194b5dfef381f3f. * Revert "Update from Shopify for theme dawn/release/15.0.0" This reverts commit 64e1d8ef792fb4a2f95ae258b7250813d23b7bca. * Revert "Update from Shopify for theme dawn/release/15.0.0" This reverts commit a8a7529234296fe6313ea2ed5b1dcf187fef4408. --------- Co-authored-by: Ludo Co-authored-by: Arthur <48017311+Roi-Arthur@users.noreply.github.com> Co-authored-by: Lars Hoffbeck Co-authored-by: shopify[bot] <79544226+shopify[bot]@users.noreply.github.com> --- assets/constants.js | 5 - assets/global.js | 20 +- assets/media-gallery.js | 6 +- assets/product-info.js | 73 +- sections/featured-product.liquid | 883 ++++++++++++------------ sections/footer.liquid | 4 +- sections/main-article.liquid | 2 +- sections/main-cart-footer.liquid | 26 +- sections/main-cart-items.liquid | 4 +- sections/main-order.liquid | 20 +- sections/main-product.liquid | 6 + snippets/cart-drawer.liquid | 28 +- snippets/product-variant-options.liquid | 4 - snippets/quick-order-list-row.liquid | 12 +- 14 files changed, 549 insertions(+), 544 deletions(-) diff --git a/assets/constants.js b/assets/constants.js index 4500201d336..8c405e63e66 100644 --- a/assets/constants.js +++ b/assets/constants.js @@ -6,9 +6,4 @@ const PUB_SUB_EVENTS = { optionValueSelectionChange: 'option-value-selection-change', variantChange: 'variant-change', cartError: 'cart-error', - sectionRefreshed: 'section-refreshed', -}; - -const SECTION_REFRESH_RESOURCE_TYPE = { - product: 'product', }; diff --git a/assets/global.js b/assets/global.js index 1c962415bca..ce13bf6514a 100644 --- a/assets/global.js +++ b/assets/global.js @@ -1059,8 +1059,7 @@ class VariantSelects extends HTMLElement { connectedCallback() { this.addEventListener('change', (event) => { const target = this.getInputForEventTarget(event.target); - this.currentVariant = this.getVariantData(target.id); - this.updateSelectedSwatchValue(event); + this.updateSelectionMetadata(event); publish(PUB_SUB_EVENTS.optionValueSelectionChange, { data: { @@ -1072,10 +1071,15 @@ class VariantSelects extends HTMLElement { }); } - updateSelectedSwatchValue({ target }) { + updateSelectionMetadata({ target }) { const { value, tagName } = target; if (tagName === 'SELECT' && target.selectedOptions.length) { + Array.from(target.options) + .find((option) => option.getAttribute('selected')) + .removeAttribute('selected'); + target.selectedOptions[0].setAttribute('selected', 'selected'); + const swatchValue = target.selectedOptions[0].dataset.optionSwatchValue; const selectedDropdownSwatchValue = target .closest('.product-form__input') @@ -1103,16 +1107,8 @@ class VariantSelects extends HTMLElement { return target.tagName === 'SELECT' ? target.selectedOptions[0] : target; } - getVariantData(inputId) { - return JSON.parse(this.getVariantDataElement(inputId).textContent); - } - - getVariantDataElement(inputId) { - return this.querySelector(`script[type="application/json"][data-resource="${inputId}"]`); - } - get selectedOptionValues() { - return Array.from(this.querySelectorAll('select, fieldset input:checked')).map( + return Array.from(this.querySelectorAll('select option[selected], fieldset input:checked')).map( ({ dataset }) => dataset.optionValueId ); } diff --git a/assets/media-gallery.js b/assets/media-gallery.js index 6c37538db96..c59cd4910ce 100644 --- a/assets/media-gallery.js +++ b/assets/media-gallery.js @@ -41,11 +41,13 @@ if (!customElements.get('media-gallery')) { activeMedia?.classList?.add('is-active'); if (prepend) { - activeMedia.parentElement.prepend(activeMedia); + activeMedia.parentElement.firstChild !== activeMedia && activeMedia.parentElement.prepend(activeMedia); + if (this.elements.thumbnails) { const activeThumbnail = this.elements.thumbnails.querySelector(`[data-target="${mediaId}"]`); - activeThumbnail.parentElement.prepend(activeThumbnail); + activeThumbnail.parentElement.firstChild !== activeThumbnail && activeThumbnail.parentElement.prepend(activeThumbnail); } + if (this.elements.viewer.slider) this.elements.viewer.resetPages(); } diff --git a/assets/product-info.js b/assets/product-info.js index f31d03e1159..5c362e35c12 100644 --- a/assets/product-info.js +++ b/assets/product-info.js @@ -57,15 +57,6 @@ if (!customElements.get('product-info')) { this.postProcessHtmlCallbacks.push((newNode) => { window?.Shopify?.PaymentButton?.init(); window?.ProductModel?.loadShopifyXR(); - publish(PUB_SUB_EVENTS.sectionRefreshed, { - data: { - sectionId: this.sectionId, - resource: { - type: SECTION_REFRESH_RESOURCE_TYPE.product, - id: newNode.dataset.productId, - }, - }, - }); }); } @@ -75,13 +66,16 @@ if (!customElements.get('product-info')) { this.resetProductFormState(); const productUrl = target.dataset.productUrl || this.pendingRequestUrl || this.dataset.url; + this.pendingRequestUrl = productUrl; const shouldSwapProduct = this.dataset.url !== productUrl; - const shouldFetchFullPage = !this.isFeaturedProduct && shouldSwapProduct; + const shouldFetchFullPage = this.dataset.updateUrl === 'true' && shouldSwapProduct; this.renderProductInfo({ requestUrl: this.buildRequestUrlWithParams(productUrl, selectedOptionValues, shouldFetchFullPage), targetId: target.id, - callback: shouldSwapProduct ? this.handleSwapProduct(productUrl) : this.handleUpdateProductInfo(productUrl), + callback: shouldSwapProduct + ? this.handleSwapProduct(productUrl, shouldFetchFullPage) + : this.handleUpdateProductInfo(productUrl), }); } @@ -91,33 +85,27 @@ if (!customElements.get('product-info')) { productForm?.handleErrorMessage(); } - get isFeaturedProduct() { - return this.dataset.section.includes('featured_product'); - } - - handleSwapProduct(productUrl) { + handleSwapProduct(productUrl, updateFullPage) { return (html) => { this.productModal?.remove(); - // Grab the selected variant from the new product info - const variant = this.getSelectedVariant(html.querySelector(`product-info[data-section=${this.sectionId}]`)); + const selector = updateFullPage ? "product-info[id^='MainProduct']" : 'product-info'; + const variant = this.getSelectedVariant(html.querySelector(selector)); this.updateURL(productUrl, variant?.id); - // If we are in an embedded context (quick add, featured product, etc), only swap product info. - // Otherwise, refresh the entire page content and sibling sections. - if (this.dataset.updateUrl === 'false') { + if (updateFullPage) { + document.querySelector('head title').innerHTML = html.querySelector('head title').innerHTML; + HTMLUpdateUtility.viewTransition( - this, - html.querySelector('product-info'), + document.querySelector('main'), + html.querySelector('main'), this.preProcessHtmlCallbacks, this.postProcessHtmlCallbacks ); } else { - document.querySelector('head title').innerHTML = html.querySelector('head title').innerHTML; - HTMLUpdateUtility.viewTransition( - document.querySelector('main'), - html.querySelector('main'), + this, + html.querySelector('product-info'), this.preProcessHtmlCallbacks, this.postProcessHtmlCallbacks ); @@ -129,7 +117,6 @@ if (!customElements.get('product-info')) { this.abortController?.abort(); this.abortController = new AbortController(); - this.pendingRequestUrl = requestUrl; fetch(requestUrl, { signal: this.abortController.signal }) .then((response) => response.text()) .then((responseText) => { @@ -170,11 +157,7 @@ if (!customElements.get('product-info')) { updateOptionValues(html) { const variantSelects = html.querySelector('variant-selects'); if (variantSelects) { - HTMLUpdateUtility.viewTransition( - this.variantSelectors, - variantSelects, - this.preProcessHtmlCallbacks, - ); + HTMLUpdateUtility.viewTransition(this.variantSelectors, variantSelects, this.preProcessHtmlCallbacks); } } @@ -257,10 +240,13 @@ if (!customElements.get('product-info')) { } updateMedia(html, variantFeaturedMediaId) { + if (!variantFeaturedMediaId) return; + const mediaGallerySource = this.querySelector('media-gallery ul'); const mediaGalleryDestination = html.querySelector(`media-gallery ul`); const refreshSourceData = () => { + if (this.hasAttribute('data-zoom-on-hover')) enableZoomOnHover(2); const mediaGallerySourceItems = Array.from(mediaGallerySource.querySelectorAll('li[data-media-id]')); const sourceSet = new Set(mediaGallerySourceItems.map((item) => item.dataset.mediaId)); const sourceMap = new Map( @@ -312,18 +298,16 @@ if (!customElements.get('product-info')) { }); } - if (variantFeaturedMediaId) { - // set featured media as active in the media gallery - this.querySelector(`media-gallery`)?.setActiveMedia?.( - `${this.dataset.section}-${variantFeaturedMediaId}`, - true - ); + // set featured media as active in the media gallery + this.querySelector(`media-gallery`)?.setActiveMedia?.( + `${this.dataset.section}-${variantFeaturedMediaId}`, + true + ); - // update media modal - const modalContent = this.productModal?.querySelector(`.product-media-modal__content`); - const newModalContent = html.querySelector(`product-modal .product-media-modal__content`); - if (modalContent && newModalContent) modalContent.innerHTML = newModalContent.innerHTML; - } + // update media modal + const modalContent = this.productModal?.querySelector(`.product-media-modal__content`); + const newModalContent = html.querySelector(`product-modal .product-media-modal__content`); + if (modalContent && newModalContent) modalContent.innerHTML = newModalContent.innerHTML; } setQuantityBoundries() { @@ -367,6 +351,7 @@ if (!customElements.get('product-info')) { } updateQuantityRules(sectionId, html) { + if (!this.quantityInput) return; this.setQuantityBoundries(); const quantityFormUpdated = html.getElementById(`Quantity-Form-${sectionId}`); diff --git a/sections/featured-product.liquid b/sections/featured-product.liquid index 61b5e205cd8..6821856a4ac 100644 --- a/sections/featured-product.liquid +++ b/sections/featured-product.liquid @@ -2,474 +2,481 @@ assign product = section.settings.product -%} - + + {{ 'section-main-product.css' | asset_url | stylesheet_tag }} + {{ 'section-featured-product.css' | asset_url | stylesheet_tag }} + {{ 'component-accordion.css' | asset_url | stylesheet_tag }} + {{ 'component-price.css' | asset_url | stylesheet_tag }} + {{ 'component-deferred-media.css' | asset_url | stylesheet_tag }} + {{ 'component-rating.css' | asset_url | stylesheet_tag }} + {{ 'component-volume-pricing.css' | asset_url | stylesheet_tag }} + {% unless section.settings.product.has_only_default_variant %} + {{ 'component-product-variant-picker.css' | asset_url | stylesheet_tag }} + {{ 'component-swatch.css' | asset_url | stylesheet_tag }} + {{ 'component-swatch-input.css' | asset_url | stylesheet_tag }} + {% endunless %} -{{ 'section-main-product.css' | asset_url | stylesheet_tag }} -{{ 'section-featured-product.css' | asset_url | stylesheet_tag }} -{{ 'component-accordion.css' | asset_url | stylesheet_tag }} -{{ 'component-price.css' | asset_url | stylesheet_tag }} -{{ 'component-deferred-media.css' | asset_url | stylesheet_tag }} -{{ 'component-rating.css' | asset_url | stylesheet_tag }} -{{ 'component-volume-pricing.css' | asset_url | stylesheet_tag }} -{% unless section.settings.product.has_only_default_variant %} - {{ 'component-product-variant-picker.css' | asset_url | stylesheet_tag }} - {{ 'component-swatch.css' | asset_url | stylesheet_tag }} - {{ 'component-swatch-input.css' | asset_url | stylesheet_tag }} -{% endunless %} - -{%- style -%} - .section-{{ section.id }}-padding { - padding-top: {{ section.settings.padding_top | times: 0.75 | round: 0 }}px; - padding-bottom: {{ section.settings.padding_bottom | times: 0.75 | round: 0 }}px; - } - - @media screen and (min-width: 750px) { + {%- style -%} .section-{{ section.id }}-padding { - padding-top: {{ section.settings.padding_top }}px; - padding-bottom: {{ section.settings.padding_bottom }}px; + padding-top: {{ section.settings.padding_top | times: 0.75 | round: 0 }}px; + padding-bottom: {{ section.settings.padding_bottom | times: 0.75 | round: 0 }}px; } - } -{%- endstyle -%} - - - + @media screen and (min-width: 750px) { + .section-{{ section.id }}-padding { + padding-top: {{ section.settings.padding_top }}px; + padding-bottom: {{ section.settings.padding_bottom }}px; + } + } + {%- endstyle -%} -{% comment %} TODO: assign `product.selected_or_first_available_variant` to variable and replace usage to reduce verbosity {% endcomment %} + + + -{%- assign first_3d_model = product.media | where: 'media_type', 'model' | first -%} -{%- if first_3d_model -%} - {{ 'component-product-model.css' | asset_url | stylesheet_tag }} - - -{%- endif -%} + {% comment %} TODO: assign `product.selected_or_first_available_variant` to variable and replace usage to reduce verbosity {% endcomment %} -{% assign variant_images = product.images | where: 'attached_to_variant?', true | map: 'src' %} + {%- assign first_3d_model = product.media | where: 'media_type', 'model' | first -%} + {%- if first_3d_model -%} + {{ 'component-product-model.css' | asset_url | stylesheet_tag }} + + + {%- endif -%} -
-
- -
+ - -{%- if section.settings.image_zoom == 'hover' -%} - -{%- endif %} -{%- if request.design_mode -%} - -{%- endif -%} + + {%- if section.settings.image_zoom == 'hover' -%} + + {%- endif %} + {%- if request.design_mode -%} + + {%- endif -%} -{%- if first_3d_model -%} - - -{%- endif -%} + {%- if first_3d_model -%} + + + {%- endif -%} -{%- liquid - if product.selected_or_first_available_variant.featured_media - assign seo_media = product.selected_or_first_available_variant.featured_media - else - assign seo_media = product.featured_media - endif --%} + {%- liquid + if product.selected_or_first_available_variant.featured_media + assign seo_media = product.selected_or_first_available_variant.featured_media + else + assign seo_media = product.featured_media + endif + -%} - + -{% if product.media.size > 0 %} - - -{% endif %} + {% if product.media.size > 0 %} + + + {% endif %}
{% schema %} diff --git a/sections/footer.liquid b/sections/footer.liquid index 99f67d81f4f..9bb8e578f22 100644 --- a/sections/footer.liquid +++ b/sections/footer.liquid @@ -95,7 +95,7 @@ href="{{ link.url }}" class="link link--text list-menu__item list-menu__item--link{% if link.active %} list-menu__item--active{% endif %}" > - {{ link.title }} + {{ link.title | escape }} {%- endfor -%} @@ -306,7 +306,7 @@ {%- if policy != blank -%}
  • {{ policy.title }}{{ policy.title | escape }}
  • {%- endif -%} diff --git a/sections/main-article.liquid b/sections/main-article.liquid index 9f0208d149a..9152432ac55 100644 --- a/sections/main-article.liquid +++ b/sections/main-article.liquid @@ -85,7 +85,7 @@
    {% render 'icon-arrow' %} - {{ 'blogs.article.back_to_blog' | t: title: blog.title }} + {{ 'blogs.article.back_to_blog' | t: title: blog.title | escape }}
    {%- if blog.comments_enabled? -%} diff --git a/sections/main-cart-footer.liquid b/sections/main-cart-footer.liquid index 11c2ee06129..2cfae877191 100644 --- a/sections/main-cart-footer.liquid +++ b/sections/main-cart-footer.liquid @@ -50,7 +50,7 @@ {%- for discount in cart.cart_level_discount_applications -%}
  • {%- render 'icon-discount' -%} - {{ discount.title }} + {{ discount.title | escape }} (-{{ discount.total_allocated_amount | money }})
  • {%- endfor -%} @@ -68,25 +68,37 @@ {%- if shop.shipping_policy.body == blank -%} {{ 'sections.cart.duties_and_taxes_included_shipping_at_checkout_without_policy' | t }} {%- else -%} - {{ 'sections.cart.duties_and_taxes_included_shipping_at_checkout_with_policy_html' | t: link: shop.shipping_policy.url }} - {%- endif -%} + {{ + 'sections.cart.duties_and_taxes_included_shipping_at_checkout_with_policy_html' + | t: link: shop.shipping_policy.url + }} + {%- endif -%} {%- elsif cart.duties_included == false and cart.taxes_included -%} {%- if shop.shipping_policy.body == blank -%} {{ 'sections.cart.taxes_included_shipping_at_checkout_without_policy' | t }} {%- else -%} - {{ 'sections.cart.taxes_included_shipping_at_checkout_with_policy_html' | t: link: shop.shipping_policy.url }} - {%- endif -%} + {{ + 'sections.cart.taxes_included_shipping_at_checkout_with_policy_html' + | t: link: shop.shipping_policy.url + }} + {%- endif -%} {%- elsif cart.duties_included and cart.taxes_included == false -%} {%- if shop.shipping_policy.body == blank -%} {{ 'sections.cart.duties_included_taxes_at_checkout_shipping_at_checkout_without_policy' | t }} {%- else -%} - {{ 'sections.cart.duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html' | t: link: shop.shipping_policy.url }} + {{ + 'sections.cart.duties_included_taxes_at_checkout_shipping_at_checkout_with_policy_html' + | t: link: shop.shipping_policy.url + }} {%- endif -%} {%- elsif cart.duties_included == false and cart.taxes_included == false -%} {%- if shop.shipping_policy.body == blank -%} {{ 'sections.cart.taxes_at_checkout_shipping_at_checkout_without_policy' | t }} {%- else -%} - {{ 'sections.cart.taxes_at_checkout_shipping_at_checkout_with_policy_html' | t: link: shop.shipping_policy.url }} + {{ + 'sections.cart.taxes_at_checkout_shipping_at_checkout_with_policy_html' + | t: link: shop.shipping_policy.url + }} {%- endif -%} {%- endif -%} diff --git a/sections/main-cart-items.liquid b/sections/main-cart-items.liquid index 1eb3f480aad..662faa8aa07 100644 --- a/sections/main-cart-items.liquid +++ b/sections/main-cart-items.liquid @@ -165,7 +165,7 @@ {%- for discount in item.line_level_discount_allocations -%}
  • {%- render 'icon-discount' -%} - {{ discount.discount_application.title }} + {{ discount.discount_application.title | escape }}
  • {%- endfor -%} @@ -281,7 +281,7 @@ {% render 'icon-remove' %} diff --git a/sections/main-order.liquid b/sections/main-order.liquid index 42a925650f6..012efbe1791 100644 --- a/sections/main-order.liquid +++ b/sections/main-order.liquid @@ -61,16 +61,16 @@ >
    {%- if line_item.url != blank -%} - {{ line_item.title }} + {{ line_item.title | escape }} {%- else -%} -

    {{ line_item.title }}

    +

    {{ line_item.title | escape }}

    {%- endif -%} {%- assign property_size = line_item.properties | size -%} {%- unless line_item.selling_plan_allocation == null and property_size == 0 -%}
    {%- unless line_item.product.has_only_default_variant -%} - {{ line_item.variant.title }} + {{ line_item.variant.title | escape }} {%- endunless -%} {%- unless line_item.selling_plan_allocation == null -%} @@ -103,7 +103,7 @@ - {{- discount_allocation.discount_application.title }} (- + {{- discount_allocation.discount_application.title | escape }} (- {{- discount_allocation.amount | money -}} ) @@ -245,7 +245,7 @@ - {{- discount_application.title -}} + {{- discount_application.title | escape -}} @@ -255,7 +255,7 @@ - {{- discount_application.title -}} + {{- discount_application.title | escape -}}
    @@ -265,12 +265,12 @@ {%- for shipping_method in order.shipping_methods -%} - {{ 'customer.order.shipping' | t }} ({{ shipping_method.title }}) + {{ 'customer.order.shipping' | t }} ({{ shipping_method.title | escape }}) {{ shipping_method.price | money }} @@ -279,13 +279,13 @@ {%- for tax_line in order.tax_lines -%} - {{ 'customer.order.tax' | t }} ({{ tax_line.title }} + {{ 'customer.order.tax' | t }} ({{ tax_line.title | escape }} {{ tax_line.rate | times: 100 }}%) {{ tax_line.price | money }} diff --git a/sections/main-product.liquid b/sections/main-product.liquid index 40936548ac5..1076c1562f9 100644 --- a/sections/main-product.liquid +++ b/sections/main-product.liquid @@ -2,6 +2,12 @@ id="MainProduct-{{ section.id }}" class="section-{{ section.id }}-padding gradient color-{{ section.settings.color_scheme }}" data-section="{{ section.id }}" + data-product-id="{{ product.id }}" + data-update-url="true" + data-url="{{ product.url }}" + {% if section.settings.image_zoom == 'hover' %} + data-zoom-on-hover + {% endif %} > {{ 'section-main-product.css' | asset_url | stylesheet_tag }} {{ 'component-accordion.css' | asset_url | stylesheet_tag }} diff --git a/snippets/cart-drawer.liquid b/snippets/cart-drawer.liquid index 52b2f9a4fec..70a858a7984 100644 --- a/snippets/cart-drawer.liquid +++ b/snippets/cart-drawer.liquid @@ -326,7 +326,7 @@