diff --git a/facets.libraries.yml b/facets.libraries.yml
index 84a7c46..62daaf3 100644
--- a/facets.libraries.yml
+++ b/facets.libraries.yml
@@ -14,10 +14,17 @@ drupal.facets.edit-facet:
dependencies:
- core/jquery
- core/drupal
- - core/jquery.once
drupal.facets.admin_css:
version: VERSION
css:
theme:
css/facets.admin.css: {}
+
+drupal.facets.checkbox-widget:
+ version: VERSION
+ js:
+ js/checkbox-widget.js: {}
+ dependencies:
+ - core/jquery
+ - core/drupal
diff --git a/js/checkbox-widget.js b/js/checkbox-widget.js
new file mode 100644
index 0000000..997aaca
--- /dev/null
+++ b/js/checkbox-widget.js
@@ -0,0 +1,69 @@
+/**
+ * @file
+ * Transforms links into checkboxes.
+ */
+
+(function ($) {
+
+ "use strict";
+
+ Drupal.facets = {};
+ Drupal.behaviors.facetsCheckboxWidget = {
+ attach: function (context, settings) {
+ Drupal.facets.makeCheckboxes();
+ }
+ };
+
+ /**
+ * Turns all facet links into checkboxes.
+ */
+ Drupal.facets.makeCheckboxes = function () {
+ // Find all checkbox facet links and give them a checkbox.
+ var $links = $('.js-facets-checkbox-links .facet-item a');
+ $links.once('facets-checkbox-transform').each(Drupal.facets.makeCheckbox);
+ };
+
+ /**
+ * Replace a link with a checked checkbox.
+ */
+ Drupal.facets.makeCheckbox = function () {
+ var $link = $(this);
+ var active = $link.hasClass('is-active');
+ var description = $link.html();
+ var href = $link.attr('href');
+ var id = $link.data('facet-id');
+
+ var checkbox = $('');
+ var label = $('');
+
+ checkbox.change(function (e) {
+ Drupal.facets.disableFacet($link.parents('.js-facets-checkbox-links'));
+ window.location.href = $(this).data('facetsredir');
+ });
+
+ if (active) {
+ checkbox.attr('checked', true);
+ label.find('.facet-deactivate').remove();
+ }
+
+ $link.before(checkbox).before(label).hide();
+
+ };
+
+ /**
+ * Disable all facet checkboxes in the facet and apply a 'disabled' class.
+ */
+ Drupal.facets.disableFacet = function ($facet) {
+ $facet.addClass('facets-disabled');
+ $('input.facets-checkbox').click(Drupal.facets.preventDefault);
+ $('input.facetapi-checkbox', $facet).attr('disabled', true);
+ };
+
+ /**
+ * Event listener for easy prevention of event propagation.
+ */
+ Drupal.facets.preventDefault = function (e) {
+ e.preventDefault();
+ }
+
+})(jQuery);
diff --git a/src/Form/CheckboxWidgetForm.php b/src/Form/CheckboxWidgetForm.php
deleted file mode 100644
index 33beff9..0000000
--- a/src/Form/CheckboxWidgetForm.php
+++ /dev/null
@@ -1,135 +0,0 @@
-facet = $facet;
- }
-
- /**
- * {@inheritdoc}
- */
- public function getBaseFormId() {
- return 'facets_checkbox_widget';
- }
-
- /**
- * {@inheritdoc}
- */
- public function getFormId() {
- return $this->getBaseFormId() . '__' . $this->facet->id();
- }
-
- /**
- * {@inheritdoc}
- */
- public function buildForm(array $form, FormStateInterface $form_state) {
- $facet = $this->facet;
-
- /** @var \Drupal\facets\Result\Result[] $results */
- $results = $facet->getResults();
-
- $configuration = $facet->getWidgetConfigs();
- $show_numbers = (bool) isset($configuration['show_numbers']) ? $configuration['show_numbers'] : FALSE;
- $form[$facet->getFieldAlias()] = [
- '#type' => 'checkboxes',
- '#title' => $facet->getName(),
- ];
-
- $options = [];
- foreach ($results as $result) {
- $text = $result->getDisplayValue();
- if ($show_numbers) {
- $text .= ' (' . $result->getCount() . ')';
- }
-
- $options[$result->getRawValue()] = $text;
-
- if ($result->isActive()) {
- $form[$facet->getFieldAlias()]['#default_value'][] = $result->getRawValue();
- }
- }
-
- $form[$facet->getFieldAlias()]['#options'] = $options;
-
- $form[$facet->id() . '_submit'] = [
- '#type' => 'submit',
- '#value' => 'submit',
- ];
-
- return $form;
- }
-
- /**
- * {@inheritdoc}
- */
- public function validateForm(array &$form, FormStateInterface $form_state) {}
-
- /**
- * {@inheritdoc}
- */
- public function submitForm(array &$form, FormStateInterface $form_state) {
- $values = $form_state->getValues();
- $facet = $this->facet;
-
- $result_link = FALSE;
- $active_items = [];
-
- foreach ($values[$facet->getFieldAlias()] as $key => $value) {
- if ($value !== 0) {
- $active_items[] = $value;
- }
- }
-
- foreach ($facet->getResults() as $result) {
- if (in_array($result->getRawValue(), $active_items)) {
- $result_link = $result->getUrl();
- }
- }
-
- // We have an active item, so we redirect to the page that has that facet
- // selected. This should be an absolute link because RedirectResponse is a
- // symfony class that requires a full URL.
- if ($result_link instanceof Url) {
- $result_link->setAbsolute();
- $form_state->setResponse(new RedirectResponse($result_link->toString()));
- return;
- }
-
- // The form was submitted but nothing was active in the form, we should
- // still redirect, but the url for the new page can't come from a result.
- // So we're redirecting to the facet source's page.
- $path = $facet->getFacetSource()->getPath();
- if (substr($path, 0, 1) !== '/') {
- $path = '/' . $path;
- }
- $link = Url::fromUserInput($path);
- $link->setAbsolute();
- $form_state->setResponse(new RedirectResponse($link->toString()));
- }
-
-}
diff --git a/src/Plugin/facets/widget/CheckboxWidget.php b/src/Plugin/facets/widget/CheckboxWidget.php
index 48ffe93..b22b4aa 100644
--- a/src/Plugin/facets/widget/CheckboxWidget.php
+++ b/src/Plugin/facets/widget/CheckboxWidget.php
@@ -2,11 +2,8 @@
namespace Drupal\facets\Plugin\facets\widget;
-use Drupal\Core\Form\FormStateInterface;
-use Drupal\Core\StringTranslation\StringTranslationTrait;
use Drupal\facets\FacetInterface;
-use Drupal\facets\Form\CheckboxWidgetForm;
-use Drupal\facets\Widget\WidgetInterface;
+use Drupal\facets\Result\ResultInterface;
/**
* The checkbox / radios widget.
@@ -17,44 +14,61 @@ use Drupal\facets\Widget\WidgetInterface;
* description = @Translation("A configurable widget that shows a list of checkboxes"),
* )
*/
-class CheckboxWidget implements WidgetInterface {
-
- use StringTranslationTrait;
+class CheckboxWidget extends LinksWidget {
/**
- * {@inheritdoc}
+ * The facet the widget is being built for.
+ *
+ * @var \Drupal\facets\FacetInterface
*/
- public function build(FacetInterface $facet) {
- $form_builder = \Drupal::getContainer()->get('form_builder');
- $form_object = new CheckboxWidgetForm($facet);
- return $form_builder->getForm($form_object);
- }
+ protected $facet;
/**
* {@inheritdoc}
*/
- public function buildConfigurationForm(array $form, FormStateInterface $form_state, $config) {
+ public function build(FacetInterface $facet) {
+ $this->facet = $facet;
- $form['show_numbers'] = [
- '#type' => 'checkbox',
- '#title' => $this->t('Show the amount of results'),
- ];
+ /** @var \Drupal\facets\Result\Result[] $results */
+ $results = $facet->getResults();
+ $items = [];
+
+ $configuration = $facet->getWidgetConfigs();
+ $this->showNumbers = empty($configuration['show_numbers']) ? FALSE : (bool) $configuration['show_numbers'];
- if (!is_null($config)) {
- $widget_configs = $config->get('widget_configs');
- if (isset($widget_configs['show_numbers'])) {
- $form['show_numbers']['#default_value'] = $widget_configs['show_numbers'];
+ foreach ($results as $result) {
+ if (is_null($result->getUrl())) {
+ $text = $this->extractText($result);
+ $items[] = ['#markup' => $text];
+ }
+ else {
+ $items[] = $this->buildListItems($result);
}
}
- return $form;
+ $build = [
+ '#theme' => 'item_list',
+ '#items' => $items,
+ '#attributes' => ['class' => ['js-facets-checkbox-links']],
+ '#cache' => [
+ 'contexts' => [
+ 'url.path',
+ 'url.query_args',
+ ],
+ ],
+ ];
+ $build['#attached']['library'][] = 'facets/drupal.facets.checkbox-widget';
+
+ return $build;
}
/**
* {@inheritdoc}
*/
- public function getQueryType($query_types) {
- return $query_types['string'];
+ protected function buildListItems(ResultInterface $result) {
+ $items = parent::buildListItems($result);
+ $items['#attributes']['data-facet-id'] = $this->facet->getUrlAlias() . '-' . $result->getRawValue();
+ return $items;
}
}
diff --git a/src/Tests/WidgetIntegrationTest.php b/src/Tests/WidgetIntegrationTest.php
index 871bd3d..6d3abda 100644
--- a/src/Tests/WidgetIntegrationTest.php
+++ b/src/Tests/WidgetIntegrationTest.php
@@ -69,80 +69,8 @@ class WidgetIntegrationTest extends WebTestBase {
$this->drupalPlaceBlock($block_values['plugin_id'], $block_values['settings']);
$this->drupalGet('search-api-test-fulltext');
- $this->drupalPostForm(NULL, array('type[item]' => 'item'), $this->t('submit'));
- $this->assertFieldChecked('edit-type-item');
- }
-
- /**
- * Tests multiple checkbox widgets.
- */
- public function testMultipleCheckboxWidget() {
- $facet_add_page = 'admin/config/search/facets/add-facet';
-
- $id = 'type';
- $name = 'Northern hawk-owl | type';
- $id_2 = 'keywords';
- $name_2 = 'Papuan hawk-owl | keywords';
-
- // Add a new facet.
- $form_values = [
- 'id' => $id,
- 'status' => 1,
- 'name' => $name,
- 'facet_source_id' => 'search_api_views:search_api_test_view:page_1',
- 'facet_source_configs[search_api_views:search_api_test_view:page_1][field_identifier]' => 'type',
- ];
- $this->drupalGet($facet_add_page);
- $this->drupalPostForm(NULL, ['facet_source_id' => 'search_api_views:search_api_test_view:page_1'], $this->t('Configure facet source'));
- $this->drupalPostForm(NULL, $form_values, $this->t('Save'));
- $this->drupalPostForm(NULL, ['widget' => 'checkbox'], $this->t('Save'));
-
- // Add a new facet.
- $form_values = [
- 'id' => $id_2,
- 'status' => 1,
- 'name' => $name_2,
- 'facet_source_id' => 'search_api_views:search_api_test_view:page_1',
- 'facet_source_configs[search_api_views:search_api_test_view:page_1][field_identifier]' => 'keywords',
- ];
- $this->drupalGet($facet_add_page);
- $this->drupalPostForm(NULL, ['facet_source_id' => 'search_api_views:search_api_test_view:page_1'], $this->t('Configure facet source'));
- $this->drupalPostForm(NULL, $form_values, $this->t('Save'));
- $this->drupalPostForm(NULL, ['widget' => 'checkbox'], $this->t('Save'));
-
- // Place facets as blocks.
- $block_values = ['region' => 'footer', 'id' => str_replace('_', '-', $id)];
- $this->drupalPlaceBlock('facet_block:' . $id, $block_values);
- $block_values = ['region' => 'footer', 'id' => str_replace('_', '-', $id_2)];
- $this->drupalPlaceBlock('facet_block:' . $id_2, $block_values);
-
- // Go to the test view and test that both facets are shown on the page.
- $this->drupalGet('search-api-test-fulltext');
- $this->assertText($name);
- $this->assertText($name_2);
- $this->assertText('item');
- $this->assertText('apple');
-
- // Submit the facet form and check that the form is submitted and the
- // checkbox is now checked.
- $edit = array('type[item]' => 'item');
- $this->drupalPostForm(NULL, $edit, $this->t('submit'));
- $this->assertText($name);
- $this->assertText($name_2);
- $this->assertText('item');
- $this->assertText('apple');
- $this->assertFieldChecked('edit-type-item');
-
- // Submit the second facet form and check that the form is submitted and the
- // checkbox is now checked.
- $edit = array('keywords[apple]' => 'apple');
- $this->drupalPostForm(NULL, $edit, $this->t('submit'));
- $this->assertText($name);
- $this->assertText($name_2);
- $this->assertText('item');
- $this->assertText('apple');
- $this->assertFieldChecked('edit-type-item');
- $this->assertFieldChecked('edit-keywords-apple');
+ $this->assertLink('item');
+ $this->assertLink('article');
}
/**
diff --git a/tests/src/Unit/Form/CheckboxWidgetFormTest.php b/tests/src/Unit/Form/CheckboxWidgetFormTest.php
deleted file mode 100644
index aead740..0000000
--- a/tests/src/Unit/Form/CheckboxWidgetFormTest.php
+++ /dev/null
@@ -1,140 +0,0 @@
-setUrl(new Url('test'));
- }
- $original_results[1]->setActiveState(TRUE);
-
- $this->originalResults = $original_results;
- }
-
- /**
- * Tests widget form with default settings.
- */
- public function testDefaultSettings() {
- $facet = new Facet(['id' => 'zoo_animal'], 'facet');
- $facet->setResults($this->originalResults);
- $facet->setFieldIdentifier('zoo_animal');
-
- $form_state = new FormState();
- $form_state->addBuildInfo('args', [$facet]);
- $form = [];
-
- $widget_form = new CheckboxWidgetForm($facet);
- $built_form = $widget_form->buildForm($form, $form_state);
-
- $this->assertInternalType('array', $built_form);
- $this->assertCount(4, $built_form['zoo_animal']['#options']);
- $this->assertEquals('checkboxes', $built_form['zoo_animal']['#type']);
-
- $expected_links = [
- 'llama' => 'Llama',
- 'badger' => 'Badger',
- 'duck' => 'Duck',
- 'alpaca' => 'Alpaca',
- ];
- foreach ($expected_links as $index => $value) {
- $this->assertEquals($value, $built_form['zoo_animal']['#options'][$index]);
- }
- $this->assertEquals(array('zoo_animal', 'zoo_animal_submit'), array_keys($built_form));
- }
-
- /**
- * Tests widget form, make sure hiding and showing numbers works.
- */
- public function testHideNumbers() {
- $facet = new Facet([], 'facet');
- $facet->setResults($this->originalResults);
- $facet->setFieldIdentifier('zoo__animal');
- $facet->setWidgetConfigs(['show_numbers' => 0]);
-
- $form_state = new FormState();
- $form_state->addBuildInfo('args', [$facet]);
- $form = [];
-
- $widget_form = new CheckboxWidgetForm($facet);
- $built_form = $widget_form->buildForm($form, $form_state);
-
- $this->assertInternalType('array', $built_form);
- $this->assertCount(4, $built_form['zoo__animal']['#options']);
- $expected_links = [
- 'llama' => 'Llama',
- 'badger' => 'Badger',
- 'duck' => 'Duck',
- 'alpaca' => 'Alpaca',
- ];
- foreach ($expected_links as $index => $value) {
- $this->assertEquals($value, $built_form['zoo__animal']['#options'][$index]);
- }
-
- // Enable the 'show_numbers' setting again to make sure that the switch
- // between those settings works.
- $facet->setWidgetConfigs(['show_numbers' => 1]);
-
- $built_form = $widget_form->buildForm($form, $form_state);
- $this->assertInternalType('array', $built_form);
- $this->assertCount(4, $built_form['zoo__animal']['#options']);
-
- $expected_links = [
- 'llama' => 'Llama (10)',
- 'badger' => 'Badger (20)',
- 'duck' => 'Duck (15)',
- 'alpaca' => 'Alpaca (9)',
- ];
- foreach ($expected_links as $index => $value) {
- $this->assertEquals($value, $built_form['zoo__animal']['#options'][$index]);
- }
- }
-
- /**
- * Tests form default methods.
- */
- public function testForm() {
- $facet = new Facet(['id' => 'donkey'], 'facet');
- $facet->setResults($this->originalResults);
- $facet->setFieldIdentifier('donkey');
-
- $form = new CheckboxWidgetForm($facet);
-
- $this->assertEquals('facets_checkbox_widget', $form->getBaseFormId());
- $this->assertEquals('facets_checkbox_widget__donkey', $form->getFormId());
- }
-
-}
diff --git a/tests/src/Unit/Plugin/widget/CheckboxWidgetTest.php b/tests/src/Unit/Plugin/widget/CheckboxWidgetTest.php
index c868d2d..8fc63da 100644
--- a/tests/src/Unit/Plugin/widget/CheckboxWidgetTest.php
+++ b/tests/src/Unit/Plugin/widget/CheckboxWidgetTest.php
@@ -2,12 +2,12 @@
namespace Drupal\Tests\facets\Unit\Plugin\widget;
+use Drupal\Component\Render\FormattableMarkup;
use Drupal\Core\Url;
use Drupal\facets\Entity\Facet;
use Drupal\facets\Plugin\facets\widget\CheckboxWidget;
use Drupal\facets\Result\Result;
use Drupal\Tests\UnitTestCase;
-use Symfony\Component\DependencyInjection\ContainerBuilder;
/**
* Unit test for widget.
@@ -49,35 +49,63 @@ class CheckboxWidgetTest extends UnitTestCase {
}
$this->originalResults = $original_results;
- $form_builder = $this->getMockBuilder('\Drupal\Core\Form\FormBuilder')
- ->disableOriginalConstructor()
- ->getMock();
- $form_builder->expects($this->once())
- ->method('getForm')
- ->willReturn('build');
-
- $string_translation = $this->getMockBuilder('\Drupal\Core\StringTranslation\TranslationManager')
- ->disableOriginalConstructor()
- ->getMock();
-
- $container_builder = new ContainerBuilder();
- $container_builder->set('form_builder', $form_builder);
- $container_builder->set('string_translation', $string_translation);
- \Drupal::setContainer($container_builder);
-
$this->widget = new CheckboxWidget();
}
/**
- * Tests widget with default settings.
+ * Tests widget without filters.
*/
- public function testDefaultSettings() {
+ public function testNoFilterResults() {
$facet = new Facet([], 'facet');
$facet->setResults($this->originalResults);
- $facet->setFieldIdentifier('test_field');
+ $facet->setWidgetConfigs(['show_numbers' => 1]);
+
+ $output = $this->widget->build($facet);
+
+ $this->assertInternalType('array', $output);
+ $this->assertCount(4, $output['#items']);
+
+ $this->assertEquals(['js-facets-checkbox-links'], $output['#attributes']['class']);
+
+ $expected_links = [
+ $this->buildLinkAssertion('Llama', 10),
+ $this->buildLinkAssertion('Badger', 20),
+ $this->buildLinkAssertion('Duck', 15),
+ $this->buildLinkAssertion('Alpaca', 9),
+ ];
+ foreach ($expected_links as $index => $value) {
+ $this->assertInternalType('array', $output['#items'][$index]);
+ $this->assertEquals($value, $output['#items'][$index]['#title']);
+ $this->assertInstanceOf(FormattableMarkup::class, $output['#items'][$index]['#title']);
+ $this->assertEquals('link', $output['#items'][$index]['#type']);
+ $this->assertEquals(['facet-item'], $output['#items'][$index]['#wrapper_attributes']['class']);
+ }
+ }
- $built_form = $this->widget->build($facet);
- $this->assertEquals('build', $built_form);
+ /**
+ * Build a formattable markup object to use in the other tests.
+ *
+ * @param string $text
+ * Text to display.
+ * @param int $count
+ * Number of results.
+ * @param bool $active
+ * Link is active.
+ * @param bool $show_numbers
+ * Numbers are displayed.
+ *
+ * @return \Drupal\Component\Render\FormattableMarkup
+ * Formattable markup object for link.
+ */
+ private function buildLinkAssertion($text, $count = 0, $active = FALSE, $show_numbers = TRUE) {
+ $text = new FormattableMarkup('@text', ['@text' => $text, '@count' => $count]);
+ if ($show_numbers !== FALSE) {
+ $text->string .= ' (@count)';
+ }
+ if ($active) {
+ $text->string = '(-) ' . $text->string;
+ }
+ return $text;
}
}
diff --git a/tests/src/Unit/Plugin/widget/LinksWidgetTest.php b/tests/src/Unit/Plugin/widget/LinksWidgetTest.php
index ae2b6f4..075bcb3 100644
--- a/tests/src/Unit/Plugin/widget/LinksWidgetTest.php
+++ b/tests/src/Unit/Plugin/widget/LinksWidgetTest.php
@@ -237,4 +237,5 @@ class LinksWidgetTest extends UnitTestCase {
}
return $text;
}
+
}