Измените образец поповера на обычную горизонталь на странице продукта shopify - PullRequest
0 голосов
/ 07 ноября 2018

Я не хочу, чтобы образец был поповером. Я хочу, чтобы образцы отображались так, как они упоминали в https://help.shopify.com/en/themes/customization/products/features/add-color-swatches Я следовал инструкциям на сайте. Мне не удалось найти функцию selectCallback во всех файлах темы. Я застрял здесь. Пожалуйста, помогите мне решить эту проблему.

Вот код файла js.

function(module, __webpack_exports__, __webpack_require__) {

  "use strict";

  Object.defineProperty(__webpack_exports__, "__esModule", {
    value: true
  });
  /* harmony import */
  var __WEBPACK_IMPORTED_MODULE_0__components_Popover__ = __webpack_require__(9);
  /* harmony import */
  var __WEBPACK_IMPORTED_MODULE_1__helper_Dom__ = __webpack_require__(0);
  /* harmony import */
  var __WEBPACK_IMPORTED_MODULE_2__components_VariantSelector__ = __webpack_require__(16);
  /* harmony import */
  var __WEBPACK_IMPORTED_MODULE_3__helper_Currency__ = __webpack_require__(5);
  /**
   * This component handles all the logic of switching variant, updating product meta...
   */

  var ProductVariants = function() {
    function ProductVariants(container, options) {
      var _this5 = this;

      _classCallCheck(this, ProductVariants);

      this.element = container;
      this.delegateElement = new domDelegate.Delegate(this.element);
      this.options = options;

      var jsonData = JSON.parse(this.element.querySelector('[data-product-json]').innerHTML);

      this.productData = jsonData['product'];
      this.variantsInventories = jsonData['inventories'] || {};
      this.masterSelector = this.element.querySelector('#product-select-' + this.productData['id']);

      // We init value with the first selected variant
      this.productData['variants'].forEach(function(variant) {
        if (variant['id'] === jsonData['selected_variant_id']) {
          _this5.currentVariant = variant;
          _this5.option1 = variant['option1'];
          _this5.option2 = variant['option2'];
          _this5.option3 = variant['option3'];
        }
      });

      this._attachListeners();
      this._createSelectors();
    }

    _createClass(ProductVariants, [{
      key: 'destroy',
      value: function destroy() {
        this.delegateElement.off('click');
        this.formPopovers.forEach(function(popover) {
          return popover.destroy();
        });
        this.formVariantSelectors.forEach(function(selector) {
          return selector.destroy();
        });
      }
    }, {
      key: '_attachListeners',
      value: function _attachListeners() {
        this.delegateElement.on('click', '[data-action="add-to-cart"]', this._addToCart.bind(this));
        this.delegateElement.on('click', '[data-action="decrease-quantity"]', this._decreaseQuantity.bind(this));
        this.delegateElement.on('click', '[data-action="increase-quantity"]', this._increaseQuantity.bind(this));
        this.delegateElement.on('change', '[name="quantity"]', this._validateQuantity.bind(this));
      }

      /**
       * Selectors can either be popovers or dedicated variant selectors. We therefore pre-create them all here
       */

    }, {
      key: '_createSelectors',
      value: function _createSelectors() {
        var _this6 = this;

        // Create the instances for each selector
        this.formPopovers = [];
        this.formVariantSelectors = [];

        __WEBPACK_IMPORTED_MODULE_1__helper_Dom__["default"].nodeListToArray(this.element.querySelectorAll('.OptionSelector')).forEach(function(item) {
          var popover = new __WEBPACK_IMPORTED_MODULE_0__components_Popover__["default"](item, {
            preferredPosition: 'left',
            onValueChanged: _this6._onOptionChanged.bind(_this6)
          });
          _this6.formPopovers.push(popover);
        });

        __WEBPACK_IMPORTED_MODULE_1__helper_Dom__["default"].nodeListToArray(this.element.querySelectorAll('.VariantSelector')).forEach(function(item) {
          var variantSelector = new __WEBPACK_IMPORTED_MODULE_2__components_VariantSelector__["default"](item, {
            onValueChanged: _this6._onOptionChanged.bind(_this6)
          });
          _this6.formVariantSelectors.push(variantSelector);
        });
      }

      /**
       * ---------------------------------------------------------------------------------------------------
       * CODE THAT HANDLE VARIANT CHANGES IN THE FRONT
       *
       * Please note that this code is highly dependant on the markup and classes, so make sure to NOT
       * edit this code
       * ---------------------------------------------------------------------------------------------------
       */

      /**
       * This callback is called whenever the variant changes and allows to update data about the active variant
       */

    }, {
      key: '_onVariantChanged',
      value: function _onVariantChanged(previousVariant, newVariant) {
        // 1st: the prices
        this._updateProductPrices(newVariant, previousVariant);

        // 2th: update inventory
        this._updateInventory(newVariant, previousVariant);

        // 3th: the add to cart button
        this._updateAddToCartButton(newVariant, previousVariant);

        if (window.theme.currencyConversionEnabled) {
          __WEBPACK_IMPORTED_MODULE_3__helper_Currency__["default"].convertAll(this.element);
        }

        // Finally, we send an event so that other system could hook and do their own logic
        this.element.dispatchEvent(new CustomEvent('variant:changed', {
          bubbles: true,
          detail: {
            variant: newVariant,
            previousVariant: previousVariant
          }
        }));
      }

      /**
       * Update the prices (optionally showing compare at price)
       */

    }, {
      key: '_updateProductPrices',
      value: function _updateProductPrices(newVariant, previousVariant) {
        var productMetaPrices = this.element.querySelector('.ProductMeta__PriceList');

        if (!newVariant) {
          productMetaPrices.style.display = 'none';
        } else {

          if (previousVariant && previousVariant['price'] === newVariant['price'] && previousVariant['compare_at_price'] === newVariant['compare_at_price']) {
            return; // The price do not have changed so let's return to avoid changing the DOM for nothing
          }

          productMetaPrices.innerHTML = '';

          if (newVariant['compare_at_price'] > newVariant['price']) {
            productMetaPrices.innerHTML += '<span class="ProductMeta__Price Price Price--highlight Text--subdued u-h4" data-money-convertible>' + __WEBPACK_IMPORTED_MODULE_3__helper_Currency__["default"].formatMoney(newVariant['price'], window.theme.moneyFormat) + '</span>';
            productMetaPrices.innerHTML += '<span class="ProductMeta__Price Price Price--compareAt Text--subdued u-h4" data-money-convertible>' + __WEBPACK_IMPORTED_MODULE_3__helper_Currency__["default"].formatMoney(newVariant['compare_at_price'], window.theme.moneyFormat) + '</span>';
          } else {
            productMetaPrices.innerHTML += '<span class="ProductMeta__Price Price Text--subdued u-h4" data-money-convertible>' + __WEBPACK_IMPORTED_MODULE_3__helper_Currency__["default"].formatMoney(newVariant['price'], window.theme.moneyFormat) + '</span>';
          }

          productMetaPrices.style.display = '';
        }
      }

      /**
       * Update the inventory (if needed)
       */

    }, {
      key: '_updateInventory',
      value: function _updateInventory(newVariant) {
        if (!this.options['showInventoryQuantity']) {
          return;
        }

        var productFormInventory = this.element.querySelector('.ProductForm__Inventory'),
          variantInventory = newVariant ? this.variantsInventories[newVariant['id']] : null;

        if (!newVariant || null === variantInventory['inventory_management'] || variantInventory['inventory_quantity'] <= 0 || this.options['inventoryQuantityThreshold'] > 0 && variantInventory['inventory_quantity'] > this.options['inventoryQuantityThreshold']) {
          productFormInventory.style.display = 'none';
        } else {
          productFormInventory.textContent = variantInventory['inventory_message'];
          productFormInventory.style.display = '';
        }
      }

      /**
       * Update the add to cart
       */

    }, {
      key: '_updateAddToCartButton',
      value: function _updateAddToCartButton(newVariant) {
        var addToCartButton = this.element.querySelector('.ProductForm__AddToCart'),
          shopifyPaymentButton = this.element.querySelector('.shopify-payment-button'),
          newButton = document.createElement('button');

        newButton.setAttribute('type', 'submit');
        newButton.className = 'ProductForm__AddToCart Button Button--full';

        if (!newVariant) {
          newButton.setAttribute('disabled', 'disabled');
          newButton.removeAttribute('data-action');
          newButton.classList.add('Button--secondary');
          newButton.innerHTML = window.languages.productFormUnavailable;
        } else {
          if (newVariant['available']) {
            newButton.removeAttribute('disabled');
            newButton.classList.add(this.options['showPaymentButton'] ? 'Button--secondary' : 'Button--primary');
            newButton.setAttribute('data-action', 'add-to-cart');

            if (this.options['showPriceInButton']) {
              newButton.innerHTML = '\n            <span>' + window.languages.productFormAddToCart + '</span>\n            <span class="Button__SeparatorDot"></span>\n            <span data-money-convertible>' + __WEBPACK_IMPORTED_MODULE_3__helper_Currency__["default"].formatMoney(newVariant['price'], window.theme.moneyFormat) + '</span>\n          ';
            } else {
              newButton.innerHTML = '<span>' + window.languages.productFormAddToCart + '</span>';
            }
          } else {
            newButton.setAttribute('disabled', 'disabled');
            newButton.classList.add('Button--secondary');
            newButton.removeAttribute('data-action');
            newButton.innerHTML = window.languages.productFormSoldOut;
          }
        }

        if (this.options['showPaymentButton'] && shopifyPaymentButton) {
          if (!newVariant || !newVariant['available']) {
            shopifyPaymentButton.style.display = 'none';
          } else {
            shopifyPaymentButton.style.display = 'block';
          }
        }

        // We replace the HTML instead of editing as it prevents for the CSS transition to show up
        addToCartButton.parentNode.replaceChild(newButton, addToCartButton);
      }

      /**
       * ---------------------------------------------------------------------------------------------------
       * INTERNAL CODE THAT HANDLE VARIANT CHANGES
       * ---------------------------------------------------------------------------------------------------
       */

      /**
       * Whenever an option is changed, this code fetch the corresponding active variant
       */

    }, {
      key: '_onOptionChanged',
      value: function _onOptionChanged(newValue, target, activator) {
        this['option' + target.getAttribute('data-option-position')] = newValue;

        // We change the value associated with the activator, and check if we have a color swatch
        var selectedValueElement = activator.querySelector('.ProductForm__SelectedValue'),
          colorSwatchElement = activator.querySelector('.ProductForm__ColorSwatch');

        selectedValueElement.innerHTML = newValue;

        if (colorSwatchElement) {
          // If the browser does not support a given color, it won't change it back to initial value
          if (!window.CSS || window.CSS && window.CSS.supports('background-color: ' + target.getAttribute('data-background-color'))) {
            colorSwatchElement.style.backgroundColor = target.getAttribute('data-background-color');
          } else {
            colorSwatchElement.style.backgroundColor = 'transparent';
          }

          colorSwatchElement.style.backgroundImage = 'url(' + target.getAttribute('data-background-image') + ')';

          if (newValue.toLowerCase() === 'white') {
            colorSwatchElement.classList.add('ProductForm__ColorSwatch--white');
          } else {
            colorSwatchElement.classList.remove('ProductForm__ColorSwatch--white');
          }
        }

        // Finally, we get the new variant
        var previousVariant = this.currentVariant;
        this.currentVariant = this._getCurrentVariantFromOptions();

        this._onVariantChanged(previousVariant, this.currentVariant);

        if (this.currentVariant) {
          if (this.options['enableHistoryState']) {
            this._updateHistoryState(this.currentVariant);
          }

          // We need to modify the hidden select that contain the id attribute as well
          this.masterSelector.querySelector('[selected]').removeAttribute('selected');
          this.masterSelector.querySelector('[value="' + this.currentVariant['id'] + '"]').setAttribute('selected', 'selected');
        }
      }

      /**
       * Get the active variant based on the options
       */

    }, {
      key: '_getCurrentVariantFromOptions',
      value: function _getCurrentVariantFromOptions() {
        var _this7 = this;

        var found = false;

        this.productData['variants'].forEach(function(variant) {
          if (variant['option1'] === _this7.option1 && variant['option2'] === _this7.option2 && variant['option3'] === _this7.option3) {
            found = variant;
          }
        });

        return found || null;
      }

      /**
       * Update the history state for browsers that support it
       */

    }, {
      key: '_updateHistoryState',
      value: function _updateHistoryState(variant) {
        if (!history.replaceState) {
          return;
        }


        var newUrl = window.location.protocol + '//' + window.location.host + window.location.pathname + '?variant=' + variant.id;

        window.history.replaceState({
          path: newUrl
        }, '', newUrl);
      }

      /**
       * ---------------------------------------------------------------------------------------------------
       * INTERNAL CODE THAT HANDLE PRODUCT ADD TO CART
       * ---------------------------------------------------------------------------------------------------
       */

    }, {
      key: '_addToCart',
      value: function _addToCart(event) {
        var _this8 = this;

        if (!this.options['useAjaxCart']) {
          return; // When using a cart type of page, we just simply redirect to the cart page
        }

        event.preventDefault(); // Prevent form to be submitted

        var addToCartButton = this.element.querySelector('.ProductForm__AddToCart');

        // First, we switch the status of the button
        addToCartButton.setAttribute('disabled', 'disabled');
        document.dispatchEvent(new CustomEvent('theme:loading:start'));

        // Then we add the product in Ajax
        var formElement = this.element.querySelector('form[action^="/cart/add"]'),
          formData = new FormData(formElement);

        /*
        fetch('/cart/add.js', {
          credentials: 'same-origin',
          method: 'POST',
          headers: {
            'Accept': 'application/json',
            'X-Requested-With': 'XMLHttpRequest' // This is needed as currently there is a bug in Shopify that assumes this header
          },
          body: formData
        }).then((response) => {
          document.dispatchEvent(new CustomEvent('theme:loading:end'));
           if (response.ok) {
            addToCartButton.removeAttribute('disabled');
             // We simply trigger an event so the mini-cart can re-render
            this.element.dispatchEvent(new CustomEvent('product:added', {
              bubbles: true,
              detail: {
                variant: this.currentVariant,
                quantity: parseInt(formElement.querySelector('[name="quantity"]').value)
              }
            }));
          } else {
            response.json().then((content) => {
              let errorMessageElement = document.createElement('span');
              errorMessageElement.className = 'ProductForm__Error Alert Alert--error';
              errorMessageElement.innerHTML = content['description'];
               addToCartButton.removeAttribute('disabled');
               addToCartButton.insertAdjacentElement('afterend', errorMessageElement);
               setTimeout(function() {
                errorMessageElement.remove();
              }, 2500);
            });
          }
        });*/

        // Unfortunately Shopify currently does not support fetch API for the Facebook Pixel. We therefore had to revert
        // to old style Ajax calls until this is tackled by the dev team

        function formSerialize(form) {
          var i = void 0,
            j = void 0,
            len = void 0,
            jLen = void 0,
            formElement = void 0,
            q = [];

          function urlencode(str) {
            return encodeURIComponent(str).replace(/!/g, '%21').replace(/'/g, '%27').replace(/\(/g, '%28').replace(/\)/g, '%29').replace(/\*/g, '%2A').replace(/%20/g, '+');
          }

          function addNameValue(name, value) {
            q.push(urlencode(name) + '=' + urlencode(value));
          }

          if (!form || !form.nodeName || form.nodeName.toLowerCase() !== 'form') {
            throw 'You must supply a form element';
          }

          for (i = 0, len = form.elements.length; i < len; i++) {
            formElement = form.elements[i];

            if (formElement.name === '' || formElement.disabled) {
              continue;
            }

            switch (formElement.nodeName.toLowerCase()) {
              case 'input':
                switch (formElement.type) {
                  case 'text':
                  case 'hidden':
                  case 'password':
                  case 'button': // Not submitted when submitting form manually, though jQuery does serialize this and it can be an HTML4 successful control
                  case 'submit':
                    addNameValue(formElement.name, formElement.value);
                    break;
                  case 'checkbox':
                  case 'radio':
                    if (formElement.checked) {
                      addNameValue(formElement.name, formElement.value);
                    }
                    break;
                  case 'file':
                    // addNameValue(formElement.name, formElement.value); // Will work and part of HTML4 "successful controls", but not used in jQuery
                    break;
                  case 'reset':
                    break;
                }
                break;
              case 'textarea':
                addNameValue(formElement.name, formElement.value);
                break;
              case 'select':
                switch (formElement.type) {
                  case 'select-one':
                    addNameValue(formElement.name, formElement.value);
                    break;
                  case 'select-multiple':
                    for (j = 0, jLen = formElement.options.length; j < jLen; j++) {
                      if (formElement.options[j].selected) {
                        addNameValue(formElement.name, formElement.options[j].value);
                      }
                    }
                    break;
                }
                break;
              case 'button':
                // jQuery does not submit these, though it is an HTML4 successful control
                switch (formElement.type) {
                  case 'reset':
                  case 'submit':
                  case 'button':
                    addNameValue(formElement.name, formElement.value);
                    break;
                }
                break;
            }
          }
          return q.join('&');
        }

        var httpRequest = new XMLHttpRequest();
        httpRequest.open('POST', '/cart/add.js', true);
        httpRequest.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded; charset=UTF-8');
        httpRequest.setRequestHeader('X-Requested-With', 'XMLHttpRequest');
        httpRequest.send(formSerialize(formElement));

        httpRequest.onreadystatechange = function() {
          // Process the server response here.
          if (httpRequest.readyState === XMLHttpRequest.DONE) {
            document.dispatchEvent(new CustomEvent('theme:loading:end'));

            if (httpRequest.status === 200) {
              addToCartButton.removeAttribute('disabled');

              // We simply trigger an event so the mini-cart can re-render
              _this8.element.dispatchEvent(new CustomEvent('product:added', {
                bubbles: true,
                detail: {
                  variant: _this8.currentVariant,
                  quantity: parseInt(formElement.querySelector('[name="quantity"]').value)
                }
              }));
            } else {
              var errors = JSON.parse(httpRequest['responseText']);

              var errorMessageElement = document.createElement('span');
              errorMessageElement.className = 'ProductForm__Error Alert Alert--error';
              errorMessageElement.innerHTML = errors['description'];

              addToCartButton.removeAttribute('disabled');

              addToCartButton.insertAdjacentElement('afterend', errorMessageElement);

              setTimeout(function() {
                errorMessageElement.remove();
              }, 2500);
            }
          }
        };

        event.preventDefault();
      }

      /**
       * ---------------------------------------------------------------------------------------------------
       * OTHER
       * ---------------------------------------------------------------------------------------------------
       */

      /**
       * When using the quantity selector, this can be used to decrease the quantity (be ensuring it won't be lower than 1)
       */

    }, {
      key: '_decreaseQuantity',
      value: function _decreaseQuantity(event, target) {
        target.nextElementSibling.value = Math.max(parseInt(target.nextElementSibling.value) - 1, 1);
      }

      /**
       * When using the quantity selector, this can be used to increase the quantity
       */

    }, {
      key: '_increaseQuantity',
      value: function _increaseQuantity(event, target) {
        target.previousElementSibling.value = parseInt(target.previousElementSibling.value) + 1;
      }

      /**
       * Make sure the quantity does not go below when manually changed
       */

    }, {
      key: '_validateQuantity',
      value: function _validateQuantity(event, target) {
        target.value = Math.max(parseInt(target.value) || 1, 1);
      }
    }]);

    return ProductVariants;
  }();
  /* harmony export (immutable) */

  __webpack_exports__["default"] = ProductVariants;

  /***/
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...