Untitled

 avatar
unknown
javascript
2 years ago
10 kB
6
Indexable
import '../lib/facet-remove';

class FacetFiltersForm extends HTMLElement {
  constructor() {
    super();

    this._loading = false;
    this._activeFilter = false;

    this.selectors = {
      filterBtn: '[data-filter-btn]',
      filterRemove: '[data-filter-remove]',
      filterOptionsContainer: '[data-filter-options-container]',
      mobileFilterBtn: '[data-mobile-filter-trigger]',
      mobileApplyFiltersBtn: '[data-mobile-apply-filters]',
      mobileCloseFiltersBtn: '[data-mobile-filter-close]',
      mobileFilters: '[data-mobile-filters]'
    };

    this.onActiveFilterClick = this.onActiveFilterClick.bind(this);

    const facetForm = this.querySelector('form');
    facetForm.addEventListener('input', this.onSubmitHandler.bind(this));

    this.addEventListener('click', this.onFilterBtnClick.bind(this));

    if (this.id === 'MobileFacets') {
      document
        .querySelector(this.selectors.mobileFilterBtn)
        .addEventListener('click', this.onMobileFilterPanelClick.bind(this));

      document
        .querySelector(this.selectors.mobileFilters)
        .addEventListener('click', this.onMobileApplyFiltersClick.bind(this));

      document
        .querySelector(this.selectors.mobileFilters)
        .addEventListener('click', this.onMobileFiltersCloseClick.bind(this));
    }
  }

  static setListeners() {
    const onHistoryChange = (event) => {
      const searchParams = event.state
        ? event.state.searchParams
        : FacetFiltersForm.searchParamsInitial;

      if (searchParams === FacetFiltersForm.searchParamsPrev) return;
      FacetFiltersForm.renderPage(searchParams, null, false);
    };
    window.addEventListener('popstate', onHistoryChange);
  }

  onActiveFilterClick(event) {
    event.preventDefault();

    const url =
      event.currentTarget.href.indexOf('?') === -1
        ? ''
        : event.currentTarget.href.slice(
            event.currentTarget.href.indexOf('?') + 1
          );
    FacetFiltersForm.renderPage(url);
  }

  onMobileFilterPanelClick(e) {
    e.preventDefault();

    document
      .querySelector(this.selectors.mobileFilters)
      .classList.add('active');

    document.querySelector('[data-sticky-filters]').classList.add('active');
  }

  onMobileFiltersCloseClick(e) {
    if (e.target.closest(this.selectors.mobileCloseFiltersBtn) === null) return;

    document
      .querySelector(this.selectors.mobileFilters)
      .classList.remove('active');

    document.querySelector('[data-sticky-filters]').classList.remove('active');
  }

  onMobileApplyFiltersClick(e) {
    if (e.target.closest(this.selectors.mobileApplyFiltersBtn) === null) return;

    document
      .querySelector(this.selectors.mobileFilters)
      .classList.remove('active');

    document.querySelector('[data-sticky-filters]').classList.remove('active');
  }

  createSearchParams(form) {
    const formData = new FormData(form);
    return new URLSearchParams(formData).toString();
  }

  onSubmitHandler(event) {
    event.preventDefault();

    this.loading = true;

    const sortFilterForms = document.querySelectorAll('facets-form form');
    const forms = [];
    const isMobile = event.target.closest('form').id === 'FacetsFormMobile';

    sortFilterForms.forEach((form) => {
      if (!isMobile) {
        if (
          form.id === 'FacetSortForm' ||
          form.id === 'FacetsFormDesktop' ||
          form.id === 'FacetSortDrawerForm'
        ) {
          forms.push(this.createSearchParams(form));
        }
      } else if (form.id === 'FacetsFormMobile') {
        forms.push(this.createSearchParams(form));
      }
    });

    this.onSubmitForm(forms.join('&'), event);
  }

  onSubmitForm(searchParams, event) {
    FacetFiltersForm.renderPage(searchParams, event);
  }

  onFilterBtnClick(e) {
    if (e.target.closest(this.selectors.filterBtn) === null) return;

    const btn = e.target.closest(this.selectors.filterBtn);

    this.activeFilter = btn.getAttribute('data-filter-btn');
  }

  static renderFilters(html, event) {
    const parsedHTML = new DOMParser().parseFromString(html, 'text/html');

    const facetDetailsElements = parsedHTML.querySelectorAll(
      '#FacetsFormDesktop [data-filter-options], #FacetsFormMobile [data-filter-options]'
    );

    const matchesIndex = (element) => {
      const jsFilter = event
        ? event.target.closest('[data-filter-slug]')
        : undefined;
      return jsFilter
        ? element.dataset.index === jsFilter.dataset.index
        : false;
    };
    const facetsToRender = Array.from(facetDetailsElements).filter(
      (element) => !matchesIndex(element)
    );

    facetsToRender.forEach((element) => {
      document
        .querySelectorAll(
          `[data-filter-options="${element.dataset.facetSlug}"]`
        )
        .forEach((filter) => {
          filter.innerHTML = element.innerHTML;
        });
    });

    FacetFiltersForm.renderActiveFacets(parsedHTML);
  }

  static renderActiveFacets(html) {
    const activeFacetElementSelectors = ['[data-active-filters]'];

    activeFacetElementSelectors.forEach((selector) => {
      const activeFacetsElement = html.querySelector(selector);
      if (!activeFacetsElement) return;
      document.querySelector(selector).innerHTML =
        activeFacetsElement.innerHTML;
    });
  }

  static renderProductGridContainer(html) {
    document.querySelector('[data-product-grid-container]').innerHTML =
      new DOMParser()
        .parseFromString(html, 'text/html')
        .querySelector('[data-product-grid-container]').innerHTML;

    document.querySelector('#DesktopFacets').loading = false;
    document.querySelector('#MobileFacets').loading = false;

    // if (window.shopifyWishlist) {
    //   window.shopifyWishlist.initButtons(
    //     document.querySelector('[data-product-grid-container]')
    //   );
    // }
  }

  static renderSectionFromCache(filterDataUrl, event) {
    const { html } = FacetFiltersForm.filterData.find(filterDataUrl);
    FacetFiltersForm.renderFilters(html, event);
    FacetFiltersForm.renderProductGridContainer(html);
  }

  static renderSectionFromFetch(url, event) {
    console.log('renderSectionFromFetch url => ', url);
    fetch(url)
      .then((response) => response.text())
      .then((responseText) => {
        const html = responseText;

        FacetFiltersForm.filterData = [
          ...FacetFiltersForm.filterData,
          { html, url }
        ];

        FacetFiltersForm.renderFilters(html, event);
        FacetFiltersForm.renderProductGridContainer(html);
      });
  }

  static renderPage(searchParams, event, updateURLHash = true) {
    FacetFiltersForm.searchParamsPrev = searchParams;
    const sections = FacetFiltersForm.getSections();

    sections.forEach((section) => {
      const url = `${window.location.pathname}?section_id=${section.section}&${searchParams}`;
      const filterDataUrl = (element) => element.url === url;

      if (FacetFiltersForm.filterData.some(filterDataUrl)) {
        FacetFiltersForm.renderSectionFromCache(filterDataUrl, event);
      } else {
        FacetFiltersForm.renderSectionFromFetch(url, event);
      }
    });

    if (updateURLHash) FacetFiltersForm.updateURLHash(searchParams);
  }

  static updateURLHash(searchParams) {
    window.history.pushState(
      { searchParams },
      '',
      `${window.location.pathname}${searchParams && '?'.concat(searchParams)}`
    );
  }

  static getSections() {
    return [
      {
        section: document.getElementById('product-grid').dataset.id
      }
    ];
  }

  get activeFilter() {
    return this._activeFilter;
  }

  set activeFilter(handle) {
    if (handle) {
      if (this.activeFilter && this.activeFilter === handle) {
        /**
         * Clicked on self
         */
        if (this.id === 'DesktopFacets') {
          this.querySelector(
            `[data-filter-btn="${this.activeFilter}"]`
          ).classList.remove('active');

          this.classList.remove('active');

          this.querySelector(
            `[data-filter-options="${this.activeFilter}"]`
          ).classList.remove('active');
        }

        document
          .querySelector('[data-sticky-filters]')
          .classList.remove('active');

        this._activeFilter = false;
      } else if (this.activeFilter) {
        /**
         * Click on another filter while another is already open
         */
        if (this.id === 'DesktopFacets') {
          this.querySelector(
            `[data-filter-btn="${this.activeFilter}"]`
          ).classList.remove('active');

          this.querySelector(`[data-filter-btn="${handle}"]`).classList.add(
            'active'
          );

          this.querySelector(
            `[data-filter-options="${this.activeFilter}"]`
          ).classList.remove('active');

          this.querySelector(`[data-filter-options="${handle}"]`).classList.add(
            'active'
          );
        }

        this._activeFilter = handle;
      } else {
        /**
         * No facet open yet
         */
        if (this.id === 'DesktopFacets') {
          this.querySelector(`[data-filter-btn="${handle}"]`).classList.add(
            'active'
          );

          this.classList.add('active');

          this.querySelector(`[data-filter-options="${handle}"]`).classList.add(
            'active'
          );
        }

        document.querySelector('[data-sticky-filters]').classList.add('active');

        this._activeFilter = handle;
      }
    } else {
      /**
       * Close all
       */
      if (this.id === 'DesktopFacets') {
        this.querySelector(
          `[data-filter-btn="${this.activeFilter}"]`
        ).classList.remove('active');

        this.classList.remove('active');

        this.querySelector(
          `[data-filter-options="${this.activeFilter}"]`
        ).classList.remove('active');
      }

      document
        .querySelector('[data-sticky-filters]')
        .classList.remove('active');

      this._activeFilter = false;
    }
  }

  get loading() {
    return this._loading;
  }

  set loading(val) {
    this._loading = val;

    this.classList.toggle('loading', val);
  }
}

FacetFiltersForm.filterData = [];
FacetFiltersForm.searchParamsInitial = window.location.search.slice(1);
FacetFiltersForm.searchParamsPrev = window.location.search.slice(1);
customElements.define('facets-form', FacetFiltersForm);
FacetFiltersForm.setListeners();
Editor is loading...