diff --git a/config/schema/facets.widgets.schema.yml b/config/schema/facets.widgets.schema.yml index 478a760..4820829 100644 --- a/config/schema/facets.widgets.schema.yml +++ b/config/schema/facets.widgets.schema.yml @@ -57,3 +57,7 @@ facet.widget.config.links: # "soft limit" and "show counts". facet.widget.config.checkbox: type: facet.widget.config.links + mapping: + submit_button_label: + type: label + label: 'Submit label' diff --git a/js/checkbox-widget.js b/js/checkbox-widget.js index 54b66ef..b6792c0 100644 --- a/js/checkbox-widget.js +++ b/js/checkbox-widget.js @@ -3,7 +3,7 @@ * Transforms links into checkboxes. */ -(function ($, Drupal) { +(function ($, Drupal, drupalSettings) { 'use strict'; @@ -31,9 +31,62 @@ // register handlers on that element. $widget.addClass('js-facets-widget'); + var facetSettings = drupalSettings.facets[$widget.data('drupal-facet-id')]; // Transform links to checkboxes. $widgetLinks.each(Drupal.facets.makeCheckbox); + // If disable autosubmit configuration is set, add the apply button. + if (facetSettings.disable_autosubmit) { + var $applyButton = $(''); + $applyButton.on('click', function (e) { + var $widget = $widgetLinks.closest('.js-facets-widget'); + + Drupal.facets.disableFacet($widget); + + // Build the url based on the selected checkboxes. + //var checkedLinks = $widgetLinks.siblings(':checked').siblings('a'); + var queryString = $.parseParams(window.location.href); + var currentFacetValues = []; + if (typeof queryString['f'] == 'object') { + currentFacetValues = queryString['f']; + } + + $widgetLinks.each(function () { + var $link = $(this); + var value = $widget.data('drupal-facet-alias') + ':' + $link.data('drupal-facet-item-value'); + var setted_index = $.inArray(value, currentFacetValues); + // Add the facet, if it is not already set. + if ($link.siblings('.facets-checkbox').is(':checked') && setted_index === -1) { + currentFacetValues.push(value); + // Remove the facet if set. + } else if ($link.siblings('.facets-checkbox').is(':checked') === false && setted_index !== -1) { + currentFacetValues.splice(setted_index, 1); + } + }); + + if (currentFacetValues.length > 0) { + queryString['f'] = $.extend({}, currentFacetValues); + } + else { + queryString['f'] = null; + } + var path = window.location.href.split('?')[0]; + var queryStringObj = $.extend({}, queryString); + + // Remove pager parameter as the current page could not exist with + // the new facets. + if (typeof queryStringObj.page !== 'undefined') { + queryStringObj.page = null; + } + + var href = path + '?' + $.param(queryStringObj); + + // Trigger the facet based on the built url. + $widget.trigger('facets_filter', [ href ]); + }); + $widgetLinks.parents('.facets-widget-checkbox').append($('
').append($applyButton)); + } + // We have to trigger attaching of behaviours, so that Facets JS API can // register handlers on checkbox widgets. Drupal.attachBehaviors(this.parentNode, Drupal.settings); @@ -54,6 +107,8 @@ var description = $link.html(); var href = $link.attr('href'); var id = $link.data('drupal-facet-item-id'); + var $widget = $(this).closest('.js-facets-widget'); + var facetSettings = drupalSettings.facets[$widget.data('drupal-facet-id')]; var checkbox = $('') .attr('id', id) @@ -61,14 +116,16 @@ .data('facetsredir', href); var label = $(''); - checkbox.on('change.facets', function (e) { - e.preventDefault(); + // Do not trigger facets on change when auto-submit is disabled, so we can trigger them manually clicking on the + // apply button. + if (!facetSettings.disable_autosubmit) { + checkbox.on('change.facets', function (e) { + e.preventDefault(); - var $widget = $(this).closest('.js-facets-widget'); - - Drupal.facets.disableFacet($widget); - $widget.trigger('facets_filter', [ href ]); - }); + Drupal.facets.disableFacet($widget); + $widget.trigger('facets_filter', [href]); + }); + } if (active) { checkbox.attr('checked', true); @@ -101,4 +158,104 @@ e.preventDefault(); }; -})(jQuery, Drupal); +})(jQuery, Drupal, drupalSettings); + + +// Add an URL parser to JQuery that returns an object +// This function is meant to be used with an URL like the window.location +// Use: $.parseParams('http://mysite.com/?var=string') or $.parseParams() to parse the window.location +// Simple variable: ?var=abc returns {var: "abc"} +// Simple object: ?var.length=2&var.scope=123 returns {var: {length: "2", scope: "123"}} +// Simple array: ?var[]=0&var[]=9 returns {var: ["0", "9"]} +// Array with index: ?var[0]=0&var[1]=9 returns {var: ["0", "9"]} +// Nested objects: ?my.var.is.here=5 returns {my: {var: {is: {here: "5"}}}} +// All together: ?var=a&my.var[]=b&my.cookie=no returns {var: "a", my: {var: ["b"], cookie: "no"}} +// You just cant have an object in an array, e.g. ?var[1].test=abc DOES NOT WORK +(function ($) { + // + var re = /([^&=]+)=?([^&]*)/g; + var decode = function (str) { + return decodeURIComponent(str.replace(/\+/g, ' ')); + }; + $.parseParams = function (query) { + + // recursive function to construct the result object + function createElement(params, key, value) { + key = key + ''; + + // if the key is a property + if (key.indexOf('.') !== -1) { + // extract the first part with the name of the object + var list = key.split('.'); + + // the rest of the key + var new_key = key.split(/\.(.+)?/)[1]; + + // create the object if it doesnt exist + if (!params[list[0]]) params[list[0]] = {}; + + // if the key is not empty, create it in the object + if (new_key !== '') { + createElement(params[list[0]], new_key, value); + } else console.warn('parseParams :: empty property in key "' + key + '"'); + } else + // if the key is an array + if (key.indexOf('[') !== -1) { + // extract the array name + var list = key.split('['); + key = list[0]; + + // extract the index of the array + var list = list[1].split(']'); + var index = list[0] + + // if index is empty, just push the value at the end of the array + if (index == '') { + if (!params) params = {}; + if (!params[key] || !$.isArray(params[key])) params[key] = []; + params[key].push(value); + } else + // add the value at the index (must be an integer) + { + if (!params) params = {}; + if (!params[key] || !$.isArray(params[key])) params[key] = []; + params[key][parseInt(index)] = value; + } + } else + // just normal key + { + if (!params) params = {}; + params[key] = value; + } + } + + // be sure the query is a string + query = query + ''; + + if (query === '') query = window.location + ''; + + var params = {}, e; + if (query) { + // remove # from end of query + if (query.indexOf('#') !== -1) { + query = query.substr(0, query.indexOf('#')); + } + + // remove ? at the begining of the query + if (query.indexOf('?') !== -1) { + query = query.substr(query.indexOf('?') + 1, query.length); + } else return {}; + + // empty parameters + if (query == '') return {}; + + // execute a createElement on every key and value + while (e = re.exec(query)) { + var key = decode(e[1]); + var value = decode(e[2]); + createElement(params, key, value); + } + } + return params; + }; +})(jQuery); diff --git a/src/Plugin/facets/widget/CheckboxWidget.php b/src/Plugin/facets/widget/CheckboxWidget.php index 207c1f1..6ec1abe 100644 --- a/src/Plugin/facets/widget/CheckboxWidget.php +++ b/src/Plugin/facets/widget/CheckboxWidget.php @@ -2,6 +2,9 @@ namespace Drupal\facets\Plugin\facets\widget; +use Drupal\Core\Form\FormStateInterface; +use Drupal\facets\FacetInterface; + /** * The checkbox / radios widget. * @@ -19,6 +22,45 @@ class CheckboxWidget extends LinksWidget { protected function appendWidgetLibrary(array &$build) { $build['#attributes']['class'][] = 'js-facets-checkbox-links'; $build['#attached']['library'][] = 'facets/drupal.facets.checkbox-widget'; + $build['#attached']['drupalSettings']['facets'][$this->facet->id()]['disable_autosubmit'] = $this->getConfiguration()['disable_autosubmit']; + $build['#attached']['drupalSettings']['facets'][$this->facet->id()]['submit_button_label'] = $this->getConfiguration()['submit_button_label']; + } + + /** + * {@inheritdoc} + */ + public function defaultConfiguration() { + return [ + 'disable_autosubmit' => FALSE, + 'submit_button_label' => 'Apply', + ] + parent::defaultConfiguration(); + } + + /** + * {@inheritdoc} + */ + public function buildConfigurationForm(array $form, FormStateInterface $form_state, FacetInterface $facet) { + $form = parent::buildConfigurationForm($form, $form_state, $facet); + + $form['disable_autosubmit'] = [ + '#type' => 'checkbox', + '#title' => $this->t('Disable autosubmit'), + '#description' => $this->t('Disabling autosubmit will provide a button to apply the selected facet items. Otherwise the facet will be applied immediately once a checkbox is checked.'), + '#default_value' => $this->getConfiguration()['disable_autosubmit'], + ]; + $form['submit_button_label'] = [ + '#type' => 'textfield', + '#title' => $this->t('Submit label'), + '#description' => $this->t('The label for the submit button to apply the facet.'), + '#default_value' => $this->getConfiguration()['submit_button_label'], + '#states' => [ + 'visible' => [ + ':input[name="widget_config[disable_autosubmit]"]' => ['checked' => TRUE], + ], + ], + ]; + + return $form; } }