elasticsearch_search_api-1.0.x-dev/js/search-ajaxify.js

js/search-ajaxify.js
(function ($, Drupal, drupalSettings, once) {

  'use strict';

  Drupal.esaSearch = Drupal.esaSearch || {};
  Drupal.esaSearch.dataLayer = window.dataLayer || [];
  const url = drupalSettings.elasticsearch_search_api.ajaxify.filter_url;

  Drupal.behaviors.ajaxifySiteSearch = {
    attach: function (context, settings) {
      // Bind on facets.
      let facetWrap = $('.esa-ajax .facets');
      if (facetWrap.length) {

        // Handle inputs, textfields, selects, with the data-facet attribute.
        facetWrap.find('[data-facet]').each(function (id, value) {
          $(once('elasticsearch_search_api-toggle', value)).on('ifToggled change', function (e) {

            let without;
            let clickedElement = e.target;
            if ($(e.currentTarget).attr('data-facet-hierarchy-multiple')) {
              if (clickedElement.checked) {

                // Check all children.
                $(clickedElement).parent().children('.facet-child-facets-wrapper').find('input').not(':checked').each(function (idx, child) {
                  $(child).attr('checked', true);
                });

                checkParentIfChildrenAreSelected(clickedElement);
              } else {

                // Uncheck all children.
                $(clickedElement).parent().children('.facet-child-facets-wrapper').find('input:checked').each(function (idx, child) {
                  $(child).attr('checked', false);
                });

                // Uncheck all parents.
                $(clickedElement).parents('.facet-child-facets-wrapper').siblings('input:checked').each(function (idx, child) {
                  $(child).attr('checked', false);
                });
              }
            }
            else if ($(e.currentTarget).attr('data-facet-hierarchy')) {
              if (!clickedElement.checked) {
                $(clickedElement).siblings('.facet-child-facets-wrapper').find('input:checked').each(function (idx, child) {
                  $(child).attr('checked', false);
                });
              }

              without = getWithoutForSingleValueFacet(e.target);
            }
            else if ($(e.currentTarget).attr('data-facet-single')) {
              without = getWithoutForSingleValueFacet(e.target);
            }

            filter(without);
          });
        });
      }

      let searchForm = $('[data-ajax-search-form]');
      $(once('elasticsearch_search_api-ajaxify', searchForm)).on('submit', function (e) {
        e.preventDefault();

        let without = drupalSettings.elasticsearch_search_api.retainFilter ? undefined : '*';
        filter(without);
      });

      // TODO add support for infinite pager
      let pager = $('.esa-results-wrapper').find('nav.pager');
      let pager_link = pager.find('a');
      $(once('elasticsearch_search_api-pager', pager_link)).on('click', function (e) {
        e.preventDefault();
        filter({}, $(this).attr('data-page'));
      });

      let didyoumean = $('.did-you-mean').find('a');
      $(once('elasticsearch_search_api-did-you-mean', didyoumean)).on('click', function (e) {
        e.preventDefault();
        searchForm.find('input[name="keyword"]').val($(this).text());
        filter();
      });

      /**
       * Check the parent filter when all its children are selected.
       *
       * @param {string} element
       *   HTML markup containing an input element.
       * @param {array} tids
       *   (Optional) previously selected term ids.
       */
      function checkParentIfChildrenAreSelected(element, tids = []) {

        // Remember previously (automatically) selected terms.
        tids.push($(element).data('drupal-facet-item-value'));

        var checkParent = true;
        $(element).parent().parent().parent().find('input').each(function (idx, child) {
          if (tids.includes($(child).data('drupal-facet-item-value'))) {
            return;
          }

          // When at least one element is unchecked, don't check
          // the parent + stop recursively going up the tree.
          if (!$(child).attr('checked')) {
            checkParent = false;
          }
        });

        if (checkParent) {
          $(element).parent().parent().parent().parent().parent().siblings('input').each(function (idx, child) {
            $(child).attr('checked', true);

            // Traverse recursively up the tree to make sure
            // all the necessary checkboxes are checked.
            checkParentIfChildrenAreSelected(child, tids);
          });
        }
      }

      /**
       * Block ui, collect facets, apply filtering.
       *
       * @param {string|object} without
       *   Optionally filter out a facet value, or all values with '*'.
       * @param {string} page
       *   Optionally page.
       * @param {bool} limitToSingleValue
       *   Boolean indicating if only one value should be returned, or multiple.
       */
      function filter(without, page, limitToSingleValue) {
        $.LoadingOverlay("show", {
          image: false,
          background: "rgba(255, 255, 255, 0.8)",
          custom: $("#block-ui-spinner").clone().show(),
          progress: false
        });

        let searchForm = $('[data-ajax-search-form]');

        let data = {
          keyword: searchForm.find('input[name="keyword"]').val()
        };

        let additionalQueryParameters = searchForm.find('input.hidden-query-param');
        additionalQueryParameters.each(function () {
          data[$(this).attr('name')] = $(this).val();
        });

        if (typeof page !== 'undefined') {
          data['page'] = page;
        }

        $.each(settings.elasticsearch_search_api.ajaxify.facets, function (idx, facetName) {
          data[facetName] = getSelectedFacets(facetName, without, false);
        });

        // Update the url after using facets, so the correct results are shown
        // when using the back button.
        if (typeof history.pushState === 'function') {
          history.pushState({}, '', '?' + $.param(data));
        }

        // Append the requested page number to the url, since drupal's
        // PagerManager uses the 'page' param from the incoming request.
        let paged_url = url + '?' + $.param(data);
        $.post(paged_url, data, function (data) {
          // Simulate a drupal.ajax response to correctly parse data.
          let ajaxObject = Drupal.ajax({
            url: '',
            base: false,
            element: false,
            progress: false
          });

          ajaxObject.success(data, 'success');
        }).always(function () {
          $.LoadingOverlay("hide");
        });
      }

      /**
       * Get facet values.
       *
       * @param {string} facet
       *   Facet name.
       * @param {string|object} without
       *   Optionally filter out a facet value, or all values with '*'.
       * @param {bool} limitToSingleValue
       *   Boolean indicating if only one value should be returned, or multiple.
       *
       * @return {Array}
       *   Array of facet values.
       */
      function getSelectedFacets(facet, without, limitToSingleValue) {
        let facetWrap = $('.esa-ajax .facets');
        limitToSingleValue = typeof limitToSingleValue === "undefined" ? true : limitToSingleValue;

        if (without === '*') {
          return [];
        }

        let ids = [];

        facetWrap.find('[data-facet="' + facet + '"]').each(function (idx, element) {
          const id = $(element).attr('data-drupal-facet-item-value') || $(element).val();

          if ($(element).attr('data-facet-list')) {
            $(element).find('input:checked').each(function (i, e) {
              const id = $(e).attr('data-drupal-facet-item-value');

              conditionallyPushId(facet, ids, id, without);
            });
          } else if ($(element).attr('data-facet-is-composite')) {
            if (Array.isArray(ids)) {
              ids = {};
            }
            let id = $(element).val();
            if (id !== "") {
              const key = $(element).attr('data-facet-composite-key');

              if (!ids.hasOwnProperty(key)) {
                ids[key] = [];
              }

              conditionallyPushId(facet, ids[key], id, without);
            }
          }
          else {
            conditionallyPushId(facet, ids, id, without);
          }
        });

        // If the facet is hierarchical facet,
        // only send a single value to the backend.
        if (limitToSingleValue && facetWrap.find('[data-facet="' + facet + '"]').attr('data-facet-hierarchy')) {
          ids = [ids.pop()];
        }

        return ids;
      }

      /**
       * Conditionally push an id to an array.
       *
       * @param {string} facet
       *   Facet id of the facet getting selected values for.
       * @param {array} ids
       *   Array to push to id into.
       * @param id
       *   Id to push.
       * @param {string|object} without
       *   Filter options.
       */
      function conditionallyPushId(facet, ids, id, without) {
        if (id === "") {
          // Don't push empty facets.
          return;
        }
        // Check if we should filter.
        if (typeof without !== 'undefined' && without.facet === facet) {
          if (!includes(without.values, id)) {
            ids.push(id);
          }
        } else {
          ids.push(id);
        }
      }

      /**
       * Get a without for a selected value.
       *
       * @param element
       *   Selected facet value.
       * @returns {{facet: *, value: *}|undefined}
       *   Without object or undefined if there are no active values.
       */
      function getWithoutForSingleValueFacet(element) {
        const facetId = $(element).attr('data-drupal-facet-item-id');
        const facetItemId = $(element).attr('data-drupal-facet-item-value');

        let activeFacetValues = getSelectedFacets(facetId, {}, false).filter(function (item) {
          return item !== facetItemId;
        });

        if (activeFacetValues.length) {
          return {facet: facetId, values: activeFacetValues};
        }
      }

      /**
       * Check if an array contains a value.
       *
       * @param array
       *   The array to check.
       * @param value
       *   The value to check for.
       * @returns {boolean}
       *   True if the array contains the value, false otherwise.
       */
      function includes(array, value) {
        let i = array.length;
        while (i--) {
          if (array[i] === value) {
            return true;
          }
        }
        return false;
      }

    }
  };

})(jQuery, Drupal, drupalSettings, once);

Главная | Обратная связь

drupal hosting | друпал хостинг | it patrol .inc