Skip to content

[Autocomplete] Allow plugins to be disabled through tom_select_options.plugins.<plugin> = false #401

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jul 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 28 additions & 0 deletions src/Autocomplete/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,33 @@
# CHANGELOG

## 2.28.0

- Default plugins like `clear_button` or `remove_button` can now be removed when setting their value to `false` in the `tom_select_options.plugins` option, for example:
```php
<?php
#[AsEntityAutocompleteField]
class IngredientAutocompleteType extends AbstractType
{
public function configureOptions(OptionsResolver $resolver): void
{
$resolver->setDefaults([
'class' => Ingredient::class,
'tom_select_options' => [
'plugins' => [
'clear_button' => false, // Disable the clear button
'remove_button' => false, // Disable the remove button
],
],
]);
}

public function getParent(): string
{
return BaseEntityAutocompleteType::class;
}
}
```

## 2.25.0

- Escape `querySelector` dynamic selector with `CSS.escape()` #2663
Expand Down
13 changes: 10 additions & 3 deletions src/Autocomplete/assets/dist/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ typeof SuppressedError === "function" ? SuppressedError : function (error, suppr
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};

var _default_1_instances, _default_1_getCommonConfig, _default_1_createAutocomplete, _default_1_createAutocompleteWithHtmlContents, _default_1_createAutocompleteWithRemoteData, _default_1_stripTags, _default_1_mergeConfigs, _default_1_normalizePluginsToHash, _default_1_createTomSelect;
var _default_1_instances, _default_1_getCommonConfig, _default_1_createAutocomplete, _default_1_createAutocompleteWithHtmlContents, _default_1_createAutocompleteWithRemoteData, _default_1_stripTags, _default_1_mergeConfigs, _default_1_normalizePluginsToHash, _default_1_normalizePlugins, _default_1_createTomSelect;
class default_1 extends Controller {
constructor() {
super(...arguments);
Expand Down Expand Up @@ -382,11 +382,18 @@ _default_1_normalizePluginsToHash = new WeakMap(), _default_1_instances = new We
return {
...config1,
...config2,
plugins: {
plugins: __classPrivateFieldGet(this, _default_1_instances, "m", _default_1_normalizePlugins).call(this, {
...__classPrivateFieldGet(this, _default_1_normalizePluginsToHash, "f").call(this, config1.plugins || {}),
...__classPrivateFieldGet(this, _default_1_normalizePluginsToHash, "f").call(this, config2.plugins || {}),
},
}),
};
}, _default_1_normalizePlugins = function _default_1_normalizePlugins(plugins) {
return Object.entries(plugins).reduce((acc, [pluginName, pluginOptions]) => {
if (pluginOptions !== false) {
acc[pluginName] = pluginOptions;
}
return acc;
}, {});
}, _default_1_createTomSelect = function _default_1_createTomSelect(options) {
const preConnectPayload = { options };
this.dispatchEvent('pre-connect', preConnectPayload);
Expand Down
14 changes: 12 additions & 2 deletions src/Autocomplete/assets/src/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,10 +330,10 @@ export default class extends Controller {
...config1,
...config2,
// Plugins from both configs should be merged together.
plugins: {
plugins: this.#normalizePlugins({
...this.#normalizePluginsToHash(config1.plugins || {}),
...this.#normalizePluginsToHash(config2.plugins || {}),
},
}),
};
}

Expand All @@ -358,6 +358,16 @@ export default class extends Controller {
return plugins;
};

#normalizePlugins(plugins: TPluginHash): TPluginHash {
return Object.entries(plugins).reduce((acc, [pluginName, pluginOptions]) => {
if (pluginOptions !== false) {
acc[pluginName] = pluginOptions;
}

return acc;
}, {} as TPluginHash);
}

/**
* Returns the element, but only if it's a select element.
*/
Expand Down
119 changes: 119 additions & 0 deletions src/Autocomplete/assets/test/controller.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -994,4 +994,123 @@ describe('AutocompleteController', () => {
await shortDelay(10);
expect(wasReset).toBe(false);
});

it('must disable default plugin "clear_button"', async () => {
const { tomSelect } = await startAutocompleteTest(`
<select data-testid='main-element' data-controller='autocomplete'>
<option value='1'>dog1</option>
<option value='2'>dog2</option>
<option value='3'>dog3</option>
</select>
`);

expect(tomSelect.plugins.names, 'The plugin "clear_button" must be present by default.').toEqual([
'clear_button',
]);

const { tomSelect: tomSelect2 } = await startAutocompleteTest(`
<select
data-testid='main-element'
data-controller='autocomplete'
data-autocomplete-tom-select-options-value="{&quot;plugins&quot;:{&quot;clear_button&quot;:false}}"
>
<option value='1'>dog1</option>
<option value='2'>dog2</option>
<option value='3'>dog3</option>
</select>
`);

expect(tomSelect2.plugins.names, 'The plugin "clear_button" must not be present.').toEqual([]);
});

it('must disable default plugin "remove_button"', async () => {
const { tomSelect } = await startAutocompleteTest(`
<select multiple data-testid='main-element' data-controller='autocomplete'>
<option value='1'>dog1</option>
<option value='2'>dog2</option>
<option value='3'>dog3</option>
</select>
`);

expect(tomSelect.plugins.names, 'The plugin "remove_button" must be present by default.').toEqual([
'remove_button',
]);

const { tomSelect: tomSelect2 } = await startAutocompleteTest(`
<select
multiple
data-testid='main-element'
data-controller='autocomplete'
data-autocomplete-tom-select-options-value="{&quot;plugins&quot;:{&quot;remove_button&quot;:false}}"
>
<option value='1'>dog1</option>
<option value='2'>dog2</option>
<option value='3'>dog3</option>
</select>
`);

expect(tomSelect2.plugins.names, 'The plugin "remove_button" must not be present.').toEqual([]);
});

it('adding a plugin should merge it with the common plugins list', async () => {
const { tomSelect } = await startAutocompleteTest(`
<select data-testid='main-element' data-controller='autocomplete'>
<option value='1'>dog1</option>
<option value='2'>dog2</option>
<option value='3'>dog3</option>
</select>
`);

expect(tomSelect.plugins.names, 'The plugin "remove_button" must be present by default.').toEqual([
'clear_button',
]);

const { tomSelect: tomSelect2 } = await startAutocompleteTest(`
<select
data-testid='main-element'
data-controller='autocomplete'
data-autocomplete-tom-select-options-value="{&quot;plugins&quot;:[&quot;input_autogrow&quot;]}"
>
<option value='1'>dog1</option>
<option value='2'>dog2</option>
<option value='3'>dog3</option>
</select>
`);

expect(tomSelect2.plugins.names, 'The plugin "input_autogrow" must be present too.').toEqual([
'clear_button',
'input_autogrow',
]);
});

it('adding a plugin (with configuration) should merge it with the common plugins list', async () => {
const { tomSelect } = await startAutocompleteTest(`
<select data-testid='main-element' data-controller='autocomplete'>
<option value='1'>dog1</option>
<option value='2'>dog2</option>
<option value='3'>dog3</option>
</select>
`);

expect(tomSelect.plugins.names, 'The plugin "remove_button" must be present by default.').toEqual([
'clear_button',
]);

const { tomSelect: tomSelect2 } = await startAutocompleteTest(`
<select
data-testid='main-element'
data-controller='autocomplete'
data-autocomplete-tom-select-options-value="{&quot;plugins&quot;:{&quot;input_autogrow&quot;:true}}"
>
<option value='1'>dog1</option>
<option value='2'>dog2</option>
<option value='3'>dog3</option>
</select>
`);

expect(tomSelect2.plugins.names, 'The plugin "input_autogrow" must be present too.').toEqual([
'clear_button',
'input_autogrow',
]);
});
});
Loading