Skip to content
Snippets Groups Projects
Commit ad677a82 authored by Alex Pott's avatar Alex Pott Committed by Christian Fritsch
Browse files

Issue #3089842 by alexpott, xavier.masson: Drag to re-order doesn't work without autocomplete

parent 7e694f2d
Branches 8.x-1.x
Tags 8.x-1.4
1 merge request!21Sorting when not using autocomplete
Pipeline #11236 passed
......@@ -60,7 +60,7 @@
$(this).select2(config);
// Copied from https://github.com/woocommerce/woocommerce/blob/master/assets/js/admin/wc-enhanced-select.js#L118
if (Object.prototype.hasOwnProperty.call(config, 'ajax') && config.multiple) {
if (config.multiple) {
var $select = $(this);
var $list = $select.next('.select2-container').find('ul.select2-selection__rendered');
Sortable.create($list[0], {
......
......@@ -211,6 +211,15 @@ class Select2 extends Select {
$element['#options'] = $empty_option + $element['#options'];
}
if ($element['#multiple']) {
$values = (array) ($element['#value'] ?? $element['#default_value']);
// Apply field values order on the options.
if (!empty($values)) {
$flipped_keys = array_intersect_key(array_flip($values), $element['#options']);
$element['#options'] = array_replace($flipped_keys, $element['#options']);
}
}
// Set the type from select2 to select to get proper form validation.
$element['#type'] = 'select';
......
......@@ -170,6 +170,20 @@ class Select2EntityReferenceWidget extends Select2Widget {
// with 'autocreate' or 'autocomplete' we want to ignore that.
$element['#multiple'] = $this->multiple && ((is_countable($this->options) ? count($this->options) : 0) > 1 || isset($element['#autocreate']) || $element['#autocomplete']);
if ($element['#multiple']) {
$entity_definition = $this->entityTypeManager->getDefinition($element['#target_type']);
$message = $this->t("Drag to re-order @entity_types.", ['@entity_types' => $entity_definition->getPluralLabel()]);
if (!empty($element['#description'])) {
$element['#description'] = [
'#theme' => 'item_list',
'#items' => [$element['#description'], $message],
];
}
else {
$element['#description'] = $message;
}
}
return $element;
}
......
......@@ -7,6 +7,7 @@ use Drupal\entity_test\Entity\EntityTestBundle;
use Drupal\entity_test\Entity\EntityTestMulRevPub;
use Drupal\entity_test\Entity\EntityTestWithBundle;
use Drupal\field\Entity\FieldConfig;
use Drupal\FunctionalJavascriptTests\SortableTestTrait;
use Drupal\Tests\select2\FunctionalJavascript\Select2JavascriptTestBase;
use Drupal\Tests\TestFileCreationTrait;
......@@ -16,7 +17,7 @@ use Drupal\Tests\TestFileCreationTrait;
* @group select2
*/
class Select2EntityReferenceWidgetTest extends Select2JavascriptTestBase {
use SortableTestTrait;
use TestFileCreationTrait;
/**
......@@ -433,10 +434,6 @@ class Select2EntityReferenceWidgetTest extends Select2JavascriptTestBase {
* Tests the autocomplete drag n drop.
*/
public function testAutocompleteDragnDrop(): void {
$this->markTestSkipped(
'Testing drag and drop is currently not possible due to a bug in chromedriver. See https://www.drupal.org/node/3084730.'
);
// @phpstan-ignore-next-line
$this->createField('select2', 'node', 'test', 'entity_reference', [
'target_type' => 'entity_test_mulrevpub',
......@@ -476,9 +473,76 @@ class Select2EntityReferenceWidgetTest extends Select2JavascriptTestBase {
$assert_session->waitForElement('xpath', '//li[contains(@class, "select2-results__option") and text()="gaga"]');
$page->find('xpath', '//li[contains(@class, "select2-results__option") and text()="gaga"]')->click();
$this->dragDropElement($page->find('xpath', '//li[contains(@class, "select2-selection__choice") and text()="gaga"]'), -100, 0);
$this->dragDropElement($page->find('xpath', '//li[contains(@class, "select2-selection__choice") and text()="foo"]'), 50, 0);
// Testing drag and drop needs to use the sortable test trait due to a bug
// in chromedriver. See https://www.drupal.org/node/3084730.
// phpcs:disable
// $this->dragDropElement($page->find('xpath', '//li[contains(@class, "select2-selection__choice") and text()="gaga"]'), -100, 0);
// $this->dragDropElement($page->find('xpath', '//li[contains(@class, "select2-selection__choice") and text()="foo"]'), 50, 0);
// phpcs:enable
$this->sortableAfter('.select2-selection.select2-selection--multiple ul.select2-selection__rendered > li:nth-child(2)', '.select2-selection.select2-selection--multiple ul.select2-selection__rendered > li:nth-child(3)', '.select2-selection.select2-selection--multiple ul.select2-selection__rendered');
$this->sortableAfter('.select2-selection.select2-selection--multiple ul.select2-selection__rendered > li:nth-child(1)', '.select2-selection.select2-selection--multiple ul.select2-selection__rendered > li:nth-child(3)', '.select2-selection.select2-selection--multiple ul.select2-selection__rendered');
$page->pressButton('Save');
$node = $this->getNodeByTitle('Test node', TRUE);
$this->assertEquals([
['target_id' => 3],
['target_id' => 2],
['target_id' => 1],
], $node->select2->getValue());
}
/**
* Tests the autocomplete drag n drop.
*/
public function testNoAutocompleteDragnDrop(): void {
// @phpstan-ignore-next-line
$this->createField('select2', 'node', 'test', 'entity_reference', [
'target_type' => 'entity_test_mulrevpub',
'cardinality' => -1,
], [
'handler' => 'default:entity_test_mulrevpub',
'handler_settings' => [
'auto_create' => FALSE,
],
], 'select2_entity_reference', [
'autocomplete' => FALSE,
'match_operator' => 'CONTAINS',
]);
EntityTestMulRevPub::create(['name' => 'foo'])->save();
EntityTestMulRevPub::create(['name' => 'bar'])->save();
EntityTestMulRevPub::create(['name' => 'gaga'])->save();
$page = $this->getSession()->getPage();
$assert_session = $this->assertSession();
$this->drupalGet('/node/add/test');
$page->fillField('title[0][value]', 'Test node');
$this->click('.form-item-select2 .select2-selection.select2-selection--multiple');
$page->find('css', '.select2-search__field')->setValue('fo');
$assert_session->waitForElement('xpath', '//li[contains(@class, "select2-results__option") and text()="foo"]');
$page->find('xpath', '//li[contains(@class, "select2-results__option") and text()="foo"]')->click();
$this->click('.form-item-select2 .select2-selection.select2-selection--multiple');
$page->find('css', '.select2-search__field')->setValue('ba');
$assert_session->waitForElement('xpath', '//li[contains(@class, "select2-results__option") and text()="bar"]');
$page->find('xpath', '//li[contains(@class, "select2-results__option") and text()="bar"]')->click();
$this->click('.form-item-select2 .select2-selection.select2-selection--multiple');
$page->find('css', '.select2-search__field')->setValue('ga');
$assert_session->waitForElement('xpath', '//li[contains(@class, "select2-results__option") and text()="gaga"]');
$page->find('xpath', '//li[contains(@class, "select2-results__option") and text()="gaga"]')->click();
// Testing drag and drop needs to use the sortable test trait due to a bug
// in chromedriver. See https://www.drupal.org/node/3084730.
// phpcs:disable
// $this->dragDropElement($page->find('xpath', '//li[contains(@class, "select2-selection__choice") and text()="gaga"]'), -100, 0);
// $this->dragDropElement($page->find('xpath', '//li[contains(@class, "select2-selection__choice") and text()="foo"]'), 50, 0);
// phpcs:enable
$this->sortableAfter('.select2-selection.select2-selection--multiple ul.select2-selection__rendered > li:nth-child(2)', '.select2-selection.select2-selection--multiple ul.select2-selection__rendered > li:nth-child(3)', '.select2-selection.select2-selection--multiple ul.select2-selection__rendered');
$this->sortableAfter('.select2-selection.select2-selection--multiple ul.select2-selection__rendered > li:nth-child(1)', '.select2-selection.select2-selection--multiple ul.select2-selection__rendered > li:nth-child(3)', '.select2-selection.select2-selection--multiple ul.select2-selection__rendered');
$page->pressButton('Save');
$node = $this->getNodeByTitle('Test node', TRUE);
......@@ -489,4 +553,26 @@ class Select2EntityReferenceWidgetTest extends Select2JavascriptTestBase {
], $node->select2->getValue());
}
/**
* {@inheritdoc}
*/
protected function sortableUpdate($item, $from, $to = NULL) {
$script = <<<'JS'
(function ($) {
var select2_widgets = document.querySelectorAll('.select2-widget');
select2_widgets.forEach(function (widget) {
// See js/select2.js.
var $select = $(widget);
var $list = $select.next('.select2-container').find('ul.select2-selection__rendered');
$($list.find('.select2-selection__choice').get().reverse()).each(function () {
$select.prepend($select.find('option[value="' + $(this).data('optionValue') + '"]').first());
});
});
})(jQuery)
JS;
$this->getSession()->executeScript($script);
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment