テーマコードに迅速な注文リストセクションを追加する

[迅速な注文リスト] セクションは、バージョン11.0.0以降の無料のShopifyテーマに対応しています。[迅速な注文リスト] セクションをストアに追加することを望む場合は、ストアのテーマを更新して最新バージョンにしてください。

テーマの更新や変更を望まない場合は、LiquidまたはJavascriptを使用してテーマにコードを追加することで、商品ページに迅速な注文リストを表示できます。

テーマファイルを更新する前に、テーマを複製してバックアップコピーを作成してください。

Liquidを使用した迅速な注文リストコードを追加する

テーマ内の以下のファイルにコードを追加することで、迅速な注文リストセクションを利用できます。

  • main-product.liquidまたはこれに相当するファイル

手順:

  1. 管理画面から [オンラインストア] > [テーマ] に移動します。

  2. 編集するテーマを見つけて、[...] ボタンをクリックしてアクションメニューを開き、[コードを編集する] をクリックします。

  3. 編集するファイルを開きます。

  4. ファイルの最下部に新しい行を作成し、以下のコードを追加します。

{% # theme-check-disable %}
{%- assign items_in_cart = cart | line_items_for: product | sum: 'quantity' -%}
{% # theme-check-enable %}

<div class="color-background-1 gradient">
  <quick-order-list
    class="page-width"
    id="quick-order-list"
    data-id="{{ section.id }}"
  >
    <form
      action="{{ routes.cart_update_url }}"
      class="quick-order-list__contents critical-hidden"
      method="post"
      id="QuickOrderList"
    >
      <div class="quick-order-list__container" id="main-variant-items">
        <div class="js-contents">
          <table class="quick-order-list__table">
            <caption class="visually-hidden">
              Quick Order List
            </caption>
            <thead>
              <tr>
                <th class="caption-with-letter-spacing" scope="col">
                  {%- if product.has_only_default_variant -%}
                    Product
                  {%- else -%}
                    Variant
                  {%- endif -%}
                </th>
                <th class="large-up-hide right caption-with-letter-spacing" scope="col">
                  {%- if product.has_only_default_variant -%}
                    Product subtotal
                  {%- else -%}
                    Variant total
                  {%- endif -%}
                </th>
                <th
                  class="quick-order-list__table-heading--wide small-hide medium-hide caption-with-letter-spacing"
                  scope="col"
                >
                  Quantity
                </th>
                <th
                  class="quick-order-list__table-heading--wide small-hide medium-hide caption-with-letter-spacing"
                  scope="col"
                >
                  Price
                </th>
                <th class="small-hide medium-hide right caption-with-letter-spacing" scope="col">
                  {%- if product.has_only_default_variant -%}
                    Product subtotal
                  {%- else -%}
                    Variant total
                  {%- endif -%}
                </th>
              </tr>
            </thead>

            <tbody>
              {%- if product.has_only_default_variant -%}
                  {% # theme-check-disable %}
                  {% assign cart_qty = cart | item_count_for_variant: product.selected_or_first_available_variant.id %}
                  {% # theme-check-enable %}
                  <tr
                    class="variant-item"
                    id="Variant-{{ product.selected_or_first_available_variant.id }}"
                    data-variant-id="{{ product.selected_or_first_available_variant.id }}"
                    data-cart-qty="{{ cart_qty }}"
                  >
                    <td class="variant-item__inner">
                        <div class="variant-item__media">
                          <div class="variant-item__image-container gradient global-media-settings{% unless product.featured_media %} variant-item__image-container--no-img {% endunless %}">
                            {% if product.featured_media %}
                              {%- assign img_height = 43 | divided_by: product.featured_media.aspect_ratio | ceil -%}
                              {{
                                product.featured_media
                                | image_url: width: 86
                                | image_tag:
                                  loading: 'lazy',
                                  fetchpriority: 'low',
                                  decoding: 'async',
                                  class: 'variant-item__image',
                                  width: 43,
                                  height: img_height,
                                  widths: '86',
                                  alt: product.featured_media.alt
                                | escape
                              }}
                            {% endif %}
                          </div>
                        </div>
                      <div class="small-hide medium-hide">
                        <span class="variant-item__name h4 break">{{ product.title | escape }}</span>
                        {%- if product.sku -%}
                          <span class="variant-item__sku break">{{ product.selected_or_first_available_variant.sku | escape }}</span>
                        {%- endif -%}
                      </div>
                    </td>

                    <td class="variant-item__details large-up-hide">
                      <div class="variant-item__info">
                        <span class="variant-item__name h4 break">{{ variant.title | escape }}</span>
                        {%- if product.selected_or_first_available_variant.sku -%}
                          <span class="variant-item__sku break">{{ product.selected_or_first_available_variant.sku | escape }}</span>
                        {%- endif -%}
                      </div>

                      {%- assign item_price = product.selected_or_first_available_variant.price | money -%}
                      {%- if product.selected_or_first_available_variant.compare_at_price -%}
                        <dl class="variant-item__discounted-prices">
                          <dt class="visually-hidden">
                            Regular price
                          </dt>
                          <dd>
                            <s class="variant-item__old-price price price--end">
                              {{ product.selected_or_first_available_variant.compare_at_price | money }}
                            </s>
                          </dd>
                          <dt class="visually-hidden">
                            Sale price
                          </dt>
                          <dd class="price">
                             <span class="price">
                               {{ item_price }}/ea
                             </span>
                          </dd>
                        </dl>
                      {%- else -%}
                          <span class="price">
                            {{ item_price }}/ea
                          </span>
                      {%- endif -%}

                      {%- if product.selected_or_first_available_variant.available and product.selected_or_first_available_variant.unit_price_measurement -%}
                        <div class="unit-price caption">
                          <span class="visually-hidden">Unit price</span>
                          {{ product.selected_or_first_available_variant.unit_price | money }}
                          <span aria-hidden="true">/</span>
                          <span class="visually-hidden">&nbsp;per&nbsp;</span>
                          {%- if product.selected_or_first_available_variant.unit_price_measurement.reference_value != 1 -%}
                            {{- product.selected_or_first_available_variant.unit_price_measurement.reference_value -}}
                          {%- endif -%}
                          {{ product.selected_or_first_available_variant.unit_price_measurement.reference_unit }}
                        </div>
                      {%- endif -%}
                    </td>

                    <td class="variant-item__totals right large-up-hide">
                      {%- render 'loading-overlay' -%}
                      {% comment %} TODO: enable theme-check once `line_items_for` is accepted as valid filter {% endcomment %}
                      {% # theme-check-disable %}
                      <span class="price">{{ cart | line_items_for: product.selected_or_first_available_variant | sum: 'original_line_price' | money }}</span>
                      {% # theme-check-enable %}
                    </td>

                    <td class="variant-item__quantity">
                      <quantity-popover>
                        <div class="variant-item__quantity-wrapper quantity-popover-wrapper variant-item__quantity-wrapper--no-info">
                          <label class="visually-hidden" for="Quantity-{{ variant.id }}">
                            Quantity
                          </label>
                          <div class="quantity-popover-container">
                            {%- if product.selected_or_first_available_variant.available == false -%}
                              <span class="variant-item__sold-out h4"> Sold out </span>
                            {%- else -%}
                              {% comment %} TODO: Remove theme check {% endcomment %}
                              {% # theme-check-disable %}
                              {% assign cart_qty = cart | item_count_for_variant: product.selected_or_first_available_variant.id %}
                              {% # theme-check-enable %}
                              {% render 'quantity-input', variant: product.selected_or_first_available_variant %}
                            {%- endif -%}
                          </div>
                          {%- if cart_qty > 0 -%}
                            <quick-order-list-remove-button
                              id="Remove-{{ product.selected_or_first_available_variant.id }}"
                              data-index="{{ product.selected_or_first_available_variant.id }}"
                            >
                              <a
                                href="{{ product.selected_or_first_available_variant.url_to_remove }}"
                                class="button button--tertiary"
                                aria-label="Remove {{ variant.title }}"
                              >
                                {% render 'icon-remove' %}
                              </a>
                            </quick-order-list-remove-button>
                          {%- endif -%}
                        </div>
                        <div
                          class="variant-item__error large-up-hide"
                          id="Quick-order-list-item-error-mobile-{{ product.selected_or_first_available_variant.id }}"
                          role="alert"
                        >
                          <small class="variant-item__error-text"></small>
                          {% render 'icon-error' %}
                        </div>
                      </quantity-popover>
                    </td>
                    {%- assign item_price = product.selected_or_first_available_variant.price | money -%}
                    <td class="variant-item__price small-hide medium-hide">
                      {%- if variant.compare_at_price -%}
                        <dl class="variant-item__discounted-prices">
                          <dt class="visually-hidden">
                            Regular price
                          </dt>
                          <dd>
                            <s class="variant-item__old-price price price--end">
                              {{ product.selected_or_first_available_variant.compare_at_price | money }}
                            </s>
                          </dd>
                          <dt class="visually-hidden">
                            Sale price
                          </dt>
                          <dd class="price">
                             <span class="price">
                               {{ item_price }}/ea
                             </span>
                          </dd>
                        </dl>
                      {%- else -%}
                         <span class="price">
                           {{ item_price }}/ea
                         </span>
                       {%- endif -%}

                      {%- if product.selected_or_first_available_variant.available and product.selected_or_first_available_variant.unit_price_measurement -%}
                        <div class="unit-price caption">
                          <span class="visually-hidden">Unit price</span>
                          {{ variant.unit_price | money }}
                          <span aria-hidden="true">/</span>
                          <span class="visually-hidden">&nbsp;per&nbsp;</span>
                          {%- if product.selected_or_first_available_variant.unit_price_measurement.reference_value != 1 -%}
                            {{- product.selected_or_first_available_variant.unit_price_measurement.reference_value -}}
                          {%- endif -%}
                          {{ product.selected_or_first_available_variant.unit_price_measurement.reference_unit }}
                        </div>
                      {%- endif -%}
                    </td>
                    <td class="variant-item__totals right small-hide medium-hide">
                      {%- render 'loading-overlay' -%}
                      {% comment %} TODO: enable theme-check once `line_items_for` is accepted as valid filter {% endcomment %}
                      {% # theme-check-disable %}
                      <span class="price">{{ cart | line_items_for: product.selected_or_first_available_variant | sum: 'original_line_price' | money }}</span>
                      {% # theme-check-enable %}
                    </td>
                  </tr>
                  <tr class="small-hide medium-hide hidden desktop-row-error">
                    <td></td>
                    <td>
                      <div class="variant-item__error" id="Quick-order-list-item-error-desktop-{{ variant.id }}" role="alert">
                        <small class="variant-item__error-text"></small>
                        {% render 'icon-error' %}
                      </div>
                    </td>
                    <td></td>
                    <td></td>
                  </tr>
              {%- else -%}
                {%- for variant in product.variants -%}
                {% # theme-check-disable %}
                  {% assign cart_qty = cart | item_count_for_variant: variant.id %}
                 {% # theme-check-enable %}
                  <tr
                    class="variant-item"
                    id="Variant-{{ variant.id }}"
                    data-variant-id="{{ variant.id }}"
                    data-cart-qty="{{ cart_qty }}"
                  >
                    <td class="variant-item__inner">
                        <div class="variant-item__media">
                          <div class="variant-item__image-container gradient global-media-settings{% unless variant.image %} variant-item__image-container--no-img {% endunless %}">
                            {% if variant.image %}
                              {%- assign img_height = 43 | divided_by: variant.image.aspect_ratio | ceil -%}
                              {{
                                variant.image
                                | image_url: width: 86
                                | image_tag:
                                  loading: 'lazy',
                                  fetchpriority: 'low',
                                  decoding: 'async',
                                  class: 'variant-item__image',
                                  width: 43,
                                  height: img_height,
                                  widths: '86',
                                  alt: variant.image.alt
                                | escape
                              }}
                            {% endif %}
                          </div>
                        </div>
                      <div class="small-hide medium-hide">
                        <span class="variant-item__name h4 break">{{ variant.title | escape }}</span>
                        {%- if variant.sku -%}
                          <span class="variant-item__sku break">{{ variant.sku | escape }}</span>
                        {%- endif -%}
                      </div>
                    </td>

                    <td class="variant-item__details large-up-hide">
                      <div class="variant-item__info">
                        <span class="variant-item__name h4 break">{{ variant.title | escape }}</span>
                        {%- if variant.sku -%}
                          <span class="variant-item__sku break">{{ variant.sku | escape }}</span>
                        {%- endif -%}
                      </div>

                      {%- assign item_price = variant.price | money -%}
                      {%- if variant.compare_at_price -%}
                        <dl class="variant-item__discounted-prices">
                          <dt class="visually-hidden">
                            Regular price
                          </dt>
                          <dd>
                            <s class="variant-item__old-price price price--end">
                              {{ variant.compare_at_price | money }}
                            </s>
                          </dd>
                          <dt class="visually-hidden">
                            Sale price
                          </dt>
                          <dd class="price">
                             <span class="price">
                               {{ item_price }}/ea
                             </span>
                          </dd>
                        </dl>
                      {%- else -%}
                          <span class="price">
                            {{ item_price }}/ea
                          </span>
                      {%- endif -%}

                      {%- if variant.available and variant.unit_price_measurement -%}
                        <div class="unit-price caption">
                          <span class="visually-hidden">Unit price</span>
                          {{ variant.unit_price | money }}
                          <span aria-hidden="true">/</span>
                          <span class="visually-hidden">&nbsp;per&nbsp;</span>
                          {%- if variant.unit_price_measurement.reference_value != 1 -%}
                            {{- variant.unit_price_measurement.reference_value -}}
                          {%- endif -%}
                          {{ variant.unit_price_measurement.reference_unit }}
                        </div>
                      {%- endif -%}
                    </td>

                    <td class="variant-item__totals right large-up-hide">
                      {%- render 'loading-overlay' -%}
                      {% comment %} TODO: enable theme-check once `line_items_for` is accepted as valid filter {% endcomment %}
                      {% # theme-check-disable %}
                      <span class="price">{{ cart | line_items_for: variant | sum: 'original_line_price' | money }}</span>
                      {% # theme-check-enable %}
                    </td>

                    <td class="variant-item__quantity">
                      <quantity-popover>
                        <div class="variant-item__quantity-wrapper quantity-popover-wrapper variant-item__quantity-wrapper--no-info">
                          <label class="visually-hidden" for="Quantity-{{ variant.id }}">
                            Quantity
                          </label>
                          <div class="quantity-popover-container">
                            {%- if variant.available == false -%}
                              <span class="variant-item__sold-out h4">Sold out</span>
                            {%- else -%}
                              {% comment %} TODO: Remove theme check {% endcomment %}
                              {% # theme-check-disable %}
                              {% assign cart_qty = cart | item_count_for_variant: variant.id %}
                              {% # theme-check-enable %}
                              {% render 'quantity-input', variant: variant %}
                            {%- endif -%}
                          </div>
                          {%- if cart_qty > 0 -%}
                            <quick-order-list-remove-button
                              id="Remove-{{ variant.id }}"
                              data-index="{{ variant.id }}"
                            >
                              <a
                                href="{{ variant.url_to_remove }}"
                                class="button button--tertiary"
                                aria-label="Remove {{variant.title }}"
                              >
                                {% render 'icon-remove' %}
                              </a>
                            </quick-order-list-remove-button>
                          {%- endif -%}
                        </div>
                        <div
                          class="variant-item__error large-up-hide"
                          id="Quick-order-list-item-error-mobile-{{ variant.id }}"
                          role="alert"
                        >
                          <small class="variant-item__error-text"></small>
                          {% render 'icon-error' %}
                        </div>
                      </quantity-popover>
                    </td>
                    {%- assign item_price = variant.price | money -%}
                    <td class="variant-item__price small-hide medium-hide">
                      {%- if variant.compare_at_price -%}
                        <dl class="variant-item__discounted-prices">
                          <dt class="visually-hidden">
                            Regular price
                          </dt>
                          <dd>
                            <s class="variant-item__old-price price price--end">
                              {{ variant.compare_at_price | money }}
                            </s>
                          </dd>
                          <dt class="visually-hidden">
                            Sale price
                          </dt>
                          <dd class="price">
                             <span class="price">
                               {{ item_price }}/ea
                             </span>
                          </dd>
                        </dl>
                      {%- else -%}
                         <span class="price">
                           {{ item_price }}/ea
                         </span>
                       {%- endif -%}

                      {%- if variant.available and variant.unit_price_measurement -%}
                        <div class="unit-price caption">
                          <span class="visually-hidden">Unit price</span>
                          {{ variant.unit_price | money }}
                          <span aria-hidden="true">/</span>
                          <span class="visually-hidden">&nbsp;per&nbsp;</span>
                          {%- if variant.unit_price_measurement.reference_value != 1 -%}
                            {{- variant.unit_price_measurement.reference_value -}}
                          {%- endif -%}
                          {{ variant.unit_price_measurement.reference_unit }}
                        </div>
                      {%- endif -%}
                    </td>
                    <td class="variant-item__totals right small-hide medium-hide">
                      {%- render 'loading-overlay' -%}
                      {% comment %} TODO: enable theme-check once `line_items_for` is accepted as valid filter {% endcomment %}
                      {% # theme-check-disable %}
                      <span class="price">{{ cart | line_items_for: variant | sum: 'original_line_price' | money }}</span>
                      {% # theme-check-enable %}
                    </td>
                  </tr>
                  <tr class="small-hide medium-hide hidden desktop-row-error">
                    <td></td>
                    <td>
                      <div class="variant-item__error" id="Quick-order-list-item-error-desktop-{{ variant.id }}" role="alert">
                        <small class="variant-item__error-text"></small>
                        {% render 'icon-error' %}
                      </div>
                    </td>
                    <td></td>
                    <td></td>
                  </tr>

                {%- endfor -%}
              {%- endif -%}
            </tbody>
          </table>
        </div>
        <noscript>
          {%- if product.has_only_default_variant or product.variants.size == 1 -%}
            <button type="submit" class="button button--secondary right" formnovalidate form="QuickOrderList">
              Update
            </button>
          {%- endif -%}
        </noscript>
      </div>

      <p class="visually-hidden" id="quick-order-list-live-region-text" aria-live="polite" role="status"></p>
      <p
        class="visually-hidden"
        id="shopping-cart-variant-item-status"
        aria-live="polite"
        aria-hidden="true"
        role="status"
      >
        Loading...
      </p>
    </form>

    {%- if product.has_only_default_variant or product.variants.size == 1 -%}
      <span class="quick-order-list-error">
        {% comment %} Populated by JS {% endcomment %}
      </span>
    {%- else -%}
      <div class="quick-order-list__total gradient" id="quick-order-list-total">
        <div class="quick-order-list-total__info">
          <div class="quick-order-list-total__column small-hide medium-hide">
            <div class="quick-order-list-buttons">
              <a
                href="{{ routes.cart_url }} "
                class="quick-order-list__button button button--secondary small-hide medium-hide"
              >
                <span class="quick-order-list__button-text">View cart</span>
              </a>
              <div class="variant-remove-total">
                {%- render 'loading-overlay' -%}
                <quick-order-list-remove-all-button
                  class="no-js-hidden"
                  data-action="confirm"
                >
                  <button class="button button--tertiary" type="button">
                    {% render 'icon-remove' %}
                    <span class="text-body">Remove all</span>
                  </button>
                </quick-order-list-remove-all-button>
              </div>
            </div>
            <span class="quick-order-list__message caption-large" role="status">
              <span class="quick-order-list__message-icon hidden">{%- render 'icon-checkmark' -%}</span>
              <span class="quick-order-list__message-text"></span>
            </span>
            <span class="quick-order-list-error">
              {% comment %} Populated by JS {% endcomment %}
            </span>
          </div>
          <div class="quick-order-list__total-items">
            <h3>
              {{ items_in_cart }}
            </h3>
            <p class="h5">Total items</p>
          </div>
          <div class="quick-order-list-total__price">
            <noscript>
              <button type="submit" class="button button--secondary" formnovalidate form="QuickOrderList">
                Update
              </button>
            </noscript>
            <div class="totals__product-total">
              <h3 class="totals__subtotal-value">
                {% comment %} TODO: enable theme-check once `line_items_for` is accepted as valid filter {% endcomment %}
                {% # theme-check-disable %}
                {{ cart | line_items_for: product | sum: 'original_line_price' | money }}
                {% # theme-check-enable %}
              </h3>
              <p class="totals__subtotal h5">Product subtotal</p>
            </div>
            <small class="tax-note caption-large rte">
              {%- if cart.taxes_included and shop.shipping_policy.body != blank -%}
                Tax included. <a href="{{ shop.shipping_policy.url }}">Shipping</a> and discounts calculated at checkout.
              {%- elsif cart.taxes_included -%}
                Tax included and shipping and discounts calculated at checkout
              {%- elsif shop.shipping_policy.body != blank -%}
                Taxes, Discounts and <a href="{{ shop.shipping_policy.url }}">shipping</a> calculated at checkout
              {%- else -%}
                Taxes, discounts and shipping calculated at checkout
              {%- endif -%}
            </small>
          </div>
          <div class="quick-order-list-total__column large-up-hide">
            <div class="quick-order-list-buttons">
              <a
                href="{{ routes.cart_url }}"
                class="quick-order-list__button button button--secondary button--full-width"
              >
                <span class="quick-order-list__button-text">View cart</span>
              </a>
              <div class="variant-remove-total">
                {%- render 'loading-overlay' -%}
                <quick-order-list-remove-all-button
                  class="no-js-hidden"
                  data-action="confirm"
                >
                  <button class="button button--tertiary" type="button">
                    {% render 'icon-remove' %}

                    <span class="text-body">Remove all</span>
                  </button>
                </quick-order-list-remove-all-button>
              </div>
            </div>
            <span class="quick-order-list__message caption-large" role="status">
              <span class="quick-order-list__message-icon hidden">{%- render 'icon-checkmark' -%}</span>
              <span class="quick-order-list__message-text"></span>
            </span>
            <span class="quick-order-list-error">
              {% comment %} Populated by JS {% endcomment %}
            </span>
          </div>
        </div>
        <div class="quick-order-list-total__confirmation hidden">
          <span class="text-body">
            Remove all {{ items_in_cart }} items from your cart?
          </span>
          <quick-order-list-remove-all-button
            data-action="remove"
          >
            <button
              class="quick-order-list__button-confirm button button--secondary"
              type="button"
            >
              Remove all
            </button>
          </quick-order-list-remove-all-button>
          <quick-order-list-remove-all-button
            data-action="cancel"
          >
            <button
              class="quick-order-list__button-cancel button button--tertiary"
              type="button"
            >
              Cancel
            </button>
          </quick-order-list-remove-all-button>
        </div>
      </div>
    {%- endif -%}
  </quick-order-list>
  <template id="QuickOrderListErrorTemplate-{{ section.id }}">
    {% render 'icon-error' %}
    <span class="quick-order-list-error-message caption-large" role="alert"></span>
  </template>
</div>
  1. [保存] をクリックします。

Javascriptを使用した迅速な注文リストコードを追加する

バリエーションのカートの数量が変更されると、商品の小計、バリエーションの小計、発生する可能性があるエラーステータスが更新されます。更新された値はJavascriptコードを使用して取得できます。

theme.jsファイルまたはこれに相当するファイル。

手順:

  1. 管理画面から [オンラインストア] > [テーマ] に移動します。

  2. 編集するテーマを見つけて、[...] ボタンをクリックしてアクションメニューを開き、[コードを編集する] をクリックします。

  3. theme.jsファイルを開きます。

  4. ファイルの最下部に新しい行を作成し、以下のコードを追加します。

class QuickOrderListRemoveButton extends HTMLElement {
  constructor() {
    super();
    this.addEventListener('click', (event) => {
      event.preventDefault();
      const quickOrderList = this.closest('quick-order-list');
      quickOrderList.updateQuantity(this.dataset.index, 0);
    });
  }
}

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

class QuickOrderListRemoveAllButton extends HTMLElement {
  constructor() {
    super();
    const allVariants = Array.from(document.querySelectorAll('[data-variant-id]'));
    const items = {}
    let hasVariantsInCart = false;
    this.quickOrderList = this.closest('quick-order-list');

    allVariants.forEach((variant) => {
      const cartQty = parseInt(variant.dataset.cartQty);
      if (cartQty > 0) {
        hasVariantsInCart = true;
        items[parseInt(variant.dataset.variantId)] = 0;
      }
    });

    if (!hasVariantsInCart) {
      this.classList.add('hidden');
    }

    this.actions = {
      confirm: 'confirm',
      remove: 'remove',
      cancel: 'cancel'
    }

    this.addEventListener('click', (event) => {
      event.preventDefault();
      if (this.dataset.action === this.actions.confirm) {
        this.toggleConfirmation(false, true);
      } else if (this.dataset.action === this.actions.remove) {
        this.quickOrderList.updateMultipleQty(items);
        this.toggleConfirmation(true, false);
      } else if (this.dataset.action === this.actions.cancel) {
        this.toggleConfirmation(true, false);
      }
    });
  }

  toggleConfirmation(showConfirmation, showInfo) {
    this.quickOrderList.querySelector('.quick-order-list-total__confirmation').classList.toggle('hidden', showConfirmation);
    this.quickOrderList.querySelector('.quick-order-list-total__info').classList.toggle('hidden', showInfo)
  }
}

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

class QuickOrderList extends HTMLElement {
  constructor() {
    super();
    this.cart = document.querySelector('cart-drawer');
    this.actions = {
      add: 'ADD',
      update: 'UPDATE'
    }
    this.quickOrderListId = 'quick-order-list'
    this.variantItemStatusElement = document.getElementById('shopping-cart-variant-item-status');
    const form = this.querySelector('form');

    form.addEventListener('submit', this.onSubmit.bind(this));

    const debouncedOnChange = debounce((event) => {
      this.onChange(event);
    }, ON_CHANGE_DEBOUNCE_TIMER);
    this.addEventListener('change', debouncedOnChange.bind(this));
  }

  cartUpdateUnsubscriber = undefined;

  onSubmit(event) {
    event.preventDefault();
  }

  connectedCallback() {
    this.cartUpdateUnsubscriber = subscribe(PUB_SUB_EVENTS.cartUpdate, (event) => {
      if (event.source === this.quickOrderListId) {
        return;
      }
      // If its another section that made the update
      this.onCartUpdate();
    });
    this.sectionId = this.dataset.id;
  }

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

  onChange(event) {
    const inputValue = parseInt(event.target.value);
    const cartQuantity = parseInt(event.target.dataset.cartQuantity);
    const index = event.target.dataset.index;
    const name = document.activeElement.getAttribute('name');

    const quantity = inputValue - cartQuantity;

    if (cartQuantity > 0) {
      this.updateQuantity(index, inputValue, name, this.actions.update);
    } else {
      this.updateQuantity(index, quantity, name, this.actions.add);
    }
  }

  onCartUpdate() {
    fetch(`${window.location.pathname}?section_id=${this.sectionId}`)
      .then((response) => response.text())
      .then((responseText) => {
        const html = new DOMParser().parseFromString(responseText, 'text/html');
        const sourceQty = html.querySelector(this.quickOrderListId);
        this.innerHTML = sourceQty.innerHTML;
      })
      .catch(e => {
        console.error(e);
      });
  }

  getSectionsToRender() {
    return [
      {
        id: this.quickOrderListId,
        section: document.getElementById(this.quickOrderListId).dataset.id,
        selector: '.js-contents'
      },
      {
        id: 'cart-icon-bubble',
        section: 'cart-icon-bubble',
        selector: '.shopify-section'
      },
      {
        id: 'quick-order-list-live-region-text',
        section: 'cart-live-region-text',
        selector: '.shopify-section'
      },
      {
        id: 'quick-order-list-total',
        section: document.getElementById(this.quickOrderListId).dataset.id,
        selector: '.quick-order-list__total'
      },
      {
        id: 'CartDrawer',
        selector: '#CartDrawer',
        section: 'cart-drawer'
      }
    ];
  }

  renderSections(parsedState) {
    this.getSectionsToRender().forEach((section => {
      const sectionElement = document.getElementById(section.id);
      if (sectionElement && sectionElement.parentElement && sectionElement.parentElement.classList.contains('drawer')) {
        parsedState.items.length > 0 ? sectionElement.parentElement.classList.remove('is-empty') : sectionElement.parentElement.classList.add('is-empty');

        setTimeout(() => {
          document.querySelector('#CartDrawer-Overlay').addEventListener('click', this.cart.close.bind(this.cart));
        });
      }
      const elementToReplace = sectionElement && sectionElement.querySelector(section.selector) ? sectionElement.querySelector(section.selector) : sectionElement;
      if (elementToReplace) {
        elementToReplace.innerHTML =
          this.getSectionInnerHTML(parsedState.sections[section.section], section.selector);
      }
    }));

  }

  updateMultipleQty(items) {
    this.querySelector('.variant-remove-total .loading-overlay').classList.remove('hidden');

    const body = JSON.stringify({
      updates: items,
      sections: this.getSectionsToRender().map((section) => section.section),
      sections_url: window.location.pathname
    });

    this.updateMessage();
    this.setErrorMessage();

    fetch(`${routes.cart_update_url}`, { ...fetchConfig(), ...{ body } })
      .then((response) => {
        return response.text();
      })
      .then((state) => {
        const parsedState = JSON.parse(state);
        this.renderSections(parsedState);
      }).catch(() => {
        this.setErrorMessage('There was an error while updating your cart. Please try again.');
      })
      .finally(() => {
        this.querySelector('.variant-remove-total .loading-overlay').classList.add('hidden');
      });
  }

  updateQuantity(id, quantity, name, action) {
    this.toggleLoading(id, true);

    let routeUrl = routes.cart_change_url;
    let body = JSON.stringify({
      quantity,
      id,
      sections: this.getSectionsToRender().map((section) => section.section),
      sections_url: window.location.pathname
    });
    let fetchConfigType;
    if (action === this.actions.add) {
      fetchConfigType = 'javascript';
      routeUrl = routes.cart_add_url;
      body = JSON.stringify({
        items: [
          {
            quantity: parseInt(quantity),
            id: parseInt(id)
          }
        ],
        sections: this.getSectionsToRender().map((section) => section.section),
        sections_url: window.location.pathname
      });
    }

    this.updateMessage();
    this.setErrorMessage();

    fetch(`${routeUrl}`, { ...fetchConfig(fetchConfigType), ...{ body } })
      .then((response) => {
        return response.text();
      })
      .then((state) => {
        const parsedState = JSON.parse(state);
        const quantityElement = document.getElementById(`Quantity-${id}`);
        const items = document.querySelectorAll('.variant-item');

        if (parsedState.description || parsedState.errors) {
          const variantItem = document.querySelector(`[id^="Variant-${id}"] .variant-item__totals.small-hide .loading-overlay`);
          variantItem.classList.add('loading-overlay--error');
          this.resetQuantityInput(id, quantityElement);
          if (parsedState.errors) {
            this.updateLiveRegions(id, parsedState.errors);
          } else {
            this.updateLiveRegions(id, parsedState.description);
          }
          return;
        }

        this.classList.toggle('is-empty', parsedState.item_count === 0);

        this.renderSections(parsedState);

        let hasError = false;

        const currentItem = parsedState.items.find((item) => item.variant_id === parseInt(id));
        const updatedValue = currentItem ? currentItem.quantity : undefined;
        if (updatedValue && updatedValue !== quantity) {
          this.updateError(updatedValue, id);
          hasError = true;
        }

        const variantItem = document.getElementById(`Variant-${id}`);
        if (variantItem && variantItem.querySelector(`[name="${name}"]`)) {
          variantItem.querySelector(`[name="${name}"]`).focus();
        }
        publish(PUB_SUB_EVENTS.cartUpdate, { source: this.quickOrderListId, cartData: parsedState });

        if (hasError) {
          this.updateMessage();
        } else if (action === this.actions.add) {
          this.updateMessage(parseInt(quantity))
        } else if (action === this.actions.update) {
          this.updateMessage(parseInt(quantity - quantityElement.dataset.cartQuantity))
        } else {
          this.updateMessage(-parseInt(quantityElement.dataset.cartQuantity))
        }
      }).catch((error) => {
        this.querySelectorAll('.loading-overlay').forEach((overlay) => overlay.classList.add('hidden'));
        this.resetQuantityInput(id);
        console.error(error);
        this.setErrorMessage('There was an error while updating your cart. Please try again.');
      })
      .finally(() => {
        this.toggleLoading(id);
      });
  }

  resetQuantityInput(id, quantityElement) {
    const input = quantityElement ?? document.getElementById(`Quantity-${id}`);
    input.value = input.getAttribute('value');
  }

  setErrorMessage(message = null) {
    this.errorMessageTemplate = this.errorMessageTemplate ?? document.getElementById(`QuickOrderListErrorTemplate-${this.sectionId}`).cloneNode(true);
    const errorElements = document.querySelectorAll('.quick-order-list-error');

    errorElements.forEach((errorElement) => {
      errorElement.innerHTML = '';
      if (!message) return;
      const updatedMessageElement = this.errorMessageTemplate.cloneNode(true);
      updatedMessageElement.content.querySelector('.quick-order-list-error-message').innerText = message;
      errorElement.appendChild(updatedMessageElement.content);
    });
  }

  updateMessage(quantity = null) {
    const messages = this.querySelectorAll('.quick-order-list__message-text');
    const icons = this.querySelectorAll('.quick-order-list__message-icon');

    if (quantity === null || isNaN(quantity)) {
      messages.forEach(message => message.innerHTML = '');
      icons.forEach(icon => icon.classList.add('hidden'));
      return;
    }

    const isQuantityNegative = quantity < 0;
    const absQuantity = Math.abs(quantity);

    const textTemplate = isQuantityNegative
      ? (absQuantity === 1 ? `${absQuantity} item removed` : `${absQuantity} items removed`)
      : (quantity === 1 ? `${absQuantity} item added` : `${absQuantity} items added`)

    messages.forEach((msg) => msg.innerHTML = textTemplate);

    if (!isQuantityNegative) {
      icons.forEach((i) => i.classList.remove('hidden'));
    }

  }

  updateError(updatedValue, id) {
    let message = '';
    if (typeof updatedValue === 'undefined') {
      message = 'There was an error while updating your cart. Please try again.';
    } else {
      message = `You can only add ${updatedValue} of this item to your cart.`;
    }
    this.updateLiveRegions(id, message);
  }

  updateLiveRegions(id, message) {
    const variantItemErrorDesktop = document.getElementById(`Quick-order-list-item-error-desktop-${id}`);
    const variantItemErrorMobile = document.getElementById(`Quick-order-list-item-error-mobile-${id}`);
    if (variantItemErrorDesktop) {
      variantItemErrorDesktop.querySelector('.variant-item__error-text').innerHTML = message;
      variantItemErrorDesktop.closest('tr').classList.remove('hidden');
    }
    if (variantItemErrorMobile) variantItemErrorMobile.querySelector('.variant-item__error-text').innerHTML = message;

    this.variantItemStatusElement.setAttribute('aria-hidden', true);

    const cartStatus = document.getElementById('quick-order-list-live-region-text');
    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;
  }

  toggleLoading(id, enable) {
    const quickOrderList = document.getElementById(this.quickOrderListId);
    const quickOrderListItems = this.querySelectorAll(`#Variant-${id} .loading-overlay`);

    if (enable) {
      quickOrderList.classList.add('quick-order-list__container--disabled');
      [...quickOrderListItems].forEach((overlay) => overlay.classList.remove('hidden'));
      document.activeElement.blur();
      this.variantItemStatusElement.setAttribute('aria-hidden', false);
    } else {
      quickOrderList.classList.remove('quick-order-list__container--disabled');
      quickOrderListItems.forEach((overlay) => overlay.classList.add('hidden'));
    }
  }
}

customElements.define('quick-order-list', QuickOrderList);
  1. [保存] をクリックします。

Shopify Plusでビジネスを成長させませんか?

お問い合わせはこちらから