ckeditor_mentions-8.x-2.x-dev/src/Plugin/CKEditor5Plugin/Mentions.php
src/Plugin/CKEditor5Plugin/Mentions.php
<?php
namespace Drupal\ckeditor_mentions\Plugin\CKEditor5Plugin;
use Drupal\ckeditor5\Plugin\CKEditor5PluginConfigurableInterface;
use Drupal\ckeditor5\Plugin\CKEditor5PluginConfigurableTrait;
use Drupal\ckeditor5\Plugin\CKEditor5PluginDefault;
use Drupal\ckeditor_mentions\MentionsType\MentionsTypeBase;
use Drupal\ckeditor_mentions\MentionsType\MentionsTypeManager;
use Drupal\Core\Entity\EntityTypeBundleInfoInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\Core\Url;
use Drupal\editor\EditorInterface;
use Symfony\Component\DependencyInjection\ContainerInterface;
/**
* Defines the "mentions" plugin.
*
* @CKEditor5Plugin(
* id = "ckeditor_mentions_mentions",
* ckeditor5 = @CKEditor5AspectsOfCKEditor5Plugin(
* plugins = {
* "mention.Mention",
* "drupalMention.DrupalMention"
* }
* ),
* drupal = @DrupalAspectsOfCKEditor5Plugin(
* label = @Translation("Mentions"),
* library = "ckeditor_mentions/ckeditor.plugin.mention.drupal",
* elements = {
* "<a>",
* "<a class data-mention data-mention-uuid data-entity-id data-entity-uuid data-plugin href>"
* }
* )
* )
*/
class Mentions extends CKEditor5PluginDefault implements CKEditor5PluginConfigurableInterface, ContainerFactoryPluginInterface {
use CKEditor5PluginConfigurableTrait;
/**
* Mentions Plugin Manager.
*/
protected MentionsTypeManager $mentionsPluginManager;
/**
* Entity Type Bundle Info.
*/
protected EntityTypeBundleInfoInterface $entityTypeBundleInfo;
/**
* {@inheritDoc}
*/
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
$instance = new static($configuration, $plugin_id, $plugin_definition);
$instance->mentionsPluginManager = $container->get('plugin.manager.mentions_type');
$instance->entityTypeBundleInfo = $container->get('entity_type.bundle.info');
return $instance;
}
/**
* {@inheritdoc}
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state): array {
$settings = $this->configuration;
foreach ($this->mentionsPluginManager->getAllMentionsTypes() as $mentionsType => $mentionsLabel) {
$form['plugins'][$mentionsType]['#type'] = 'fieldset';
$form['plugins'][$mentionsType]['enable'] = [
'#type' => 'checkbox',
'#title' => $this->t('Enable Mentions: %type', ['%type' => $mentionsLabel]),
'#default_value' => !empty($settings['plugins'][$mentionsType]['enable']) ? $settings['plugins'][$mentionsType]['enable'] : FALSE,
'#attributes' => ['data-use-mentions--' . $mentionsType => TRUE],
];
$form['plugins'][$mentionsType]['marker'] = [
'#type' => 'textfield',
'#maxlength' => '1',
'#title' => $this->t('Marker'),
'#description' => $this->t('The character that should trigger autocompletion.'),
'#default_value' => !empty($settings['plugins'][$mentionsType]['marker']) ? $settings['plugins'][$mentionsType]['marker'] : '@',
'#states' => [
'visible' => [
':input[data-use-mentions--' . $mentionsType . ']' => ['checked' => TRUE],
],
'required' => [
':input[data-use-mentions--' . $mentionsType . ']' => ['checked' => TRUE],
],
],
];
$form['plugins'][$mentionsType]['removeMarker'] = [
'#type' => 'checkbox',
'#title' => $this->t('Remove Marker'),
'#description' => $this->t('By default, the marker that triggers the autocomplete is displayed before the mentioned entity text. This option will remove the marker from the displayed text.'),
'#default_value' => !empty($settings['plugins'][$mentionsType]['removeMarker']) ? $settings['plugins'][$mentionsType]['removeMarker'] : FALSE,
'#states' => [
'visible' => [
':input[data-use-mentions--' . $mentionsType . ']' => ['checked' => TRUE],
],
],
];
$form['plugins'][$mentionsType]['charcount'] = [
'#type' => 'number',
'#min' => 0,
'#title' => $this->t('Character Count'),
'#description' => $this->t('Enter minimum number of characters that must be typed to trigger mention match.'),
'#default_value' => $settings['plugins'][$mentionsType]['charcount'] ?? 2,
'#states' => [
'visible' => [
':input[data-use-mentions--' . $mentionsType . ']' => ['checked' => TRUE],
],
],
];
$form['plugins'][$mentionsType]['dropdownLimit'] = [
'#type' => 'number',
'#min' => 1,
'#title' => $this->t('Dropdown limit'),
'#description' => $this->t('Specify how many available elements the users be able to see in the dropdown list.'),
'#default_value' => $settings['plugins'][$mentionsType]['dropdownLimit'] ?? MentionsTypeBase::DEFAULT_DROPDOWN_LIMIT,
'#states' => [
'visible' => [
':input[data-use-mentions--' . $mentionsType . ']' => ['checked' => TRUE],
],
],
];
// Check if the mentions type corresponds to a bundable entity type.
$mentionsTypePlugin = $this->mentionsPluginManager->createInstance($mentionsType);
if ($mentionsTypePlugin->isBundable()) {
// Get available bundles for this entity type.
$entityType = $mentionsTypePlugin->getPluginDefinition()['entity_type'];
$bundles = $this->entityTypeBundleInfo->getBundleInfo($entityType);
$bundleOptions = [];
foreach ($bundles as $bundle_id => $bundle_info) {
$bundleOptions[$bundle_id] = $bundle_info['label'];
}
$form['plugins'][$mentionsType]['filterByBundle'] = [
'#type' => 'checkboxes',
'#title' => $this->t('Filter by Bundle'),
'#description' => $this->t('Select which bundles should be available for mentions. Leave empty to allow all bundles.'),
'#options' => $bundleOptions,
'#multiple' => TRUE,
'#default_value' => !empty($settings['plugins'][$mentionsType]['filterByBundle']) ? $settings['plugins'][$mentionsType]['filterByBundle'] : [],
'#states' => [
'visible' => [
':input[data-use-mentions--' . $mentionsType . ']' => ['checked' => TRUE],
],
],
];
}
}
return $form;
}
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return [
'plugins' => [],
];
}
/**
* {@inheritDoc}
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
$markers = [];
$mentionTypeFormValues = $form_state->getValue(['plugins']);
// Collect markers from enabled mention types.
foreach ($mentionTypeFormValues as $mentionsType => $mentionsTypeConfiguration) {
// Only validate enabled mention types:
if (empty($mentionsTypeConfiguration['enable'])) {
continue;
}
$marker = $mentionsTypeConfiguration['marker'];
if (isset($markers[$marker])) {
// Duplicate marker found, set validation error.
$form_state->setErrorByName(
"plugins][$mentionsType][marker",
$this->t('The marker "@marker" is already used by "@existing_type". Each mention type must have a unique marker.', [
'@marker' => $marker,
'@existing_type' => $markers[$marker],
])
);
}
else {
$markers[$marker] = $mentionsType;
}
}
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state): void {
$configuration = [];
foreach ($this->mentionsPluginManager->getAllMentionsTypes() as $mentionsType => $mentionsLabel) {
$mentionsTypeConfiguration = $form_state->getValue([
'plugins',
$mentionsType,
]);
if ($mentionsTypeConfiguration['enable']) {
$mentionsTypeConfiguration['id'] = $mentionsType;
$mentionsTypeConfiguration['enable'] = (bool) $mentionsTypeConfiguration['enable'];
$mentionsTypeConfiguration['removeMarker'] = (bool) $mentionsTypeConfiguration['removeMarker'];
$mentionsTypeConfiguration['charcount'] = (int) $mentionsTypeConfiguration['charcount'];
$mentionsTypeConfiguration['dropdownLimit'] = (int) $mentionsTypeConfiguration['dropdownLimit'];
// Handle filterByBundle for bundable entity types.
$mentionsTypePlugin = $this->mentionsPluginManager->createInstance($mentionsType);
if ($mentionsTypePlugin->isBundable()) {
// We need to filter out the 0 value because it's not a valid bundle:
$filteredBundles = array_values(array_filter($mentionsTypeConfiguration['filterByBundle'], function ($bundle) {
return $bundle != '0' ? $bundle : NULL;
}));
$mentionsTypeConfiguration['filterByBundle'] = $filteredBundles;
}
$configuration[$mentionsType] = $mentionsTypeConfiguration;
}
}
$this->configuration['plugins'] = $configuration;
}
/**
* {@inheritDoc}
*/
public function getDynamicPluginConfig(array $static_plugin_config, EditorInterface $editor): array {
$options = [];
foreach ($this->configuration['plugins'] as $settings) {
$urlParams = [
'editor_id' => $editor->id(),
'plugin_id' => $settings['id'],
'match' => '--match--',
];
$options['feeds'][] = [
'marker' => $settings['marker'],
'feed' => [
'func' => [
'name' => 'CKEditor5.drupalMention.MentionsAjax.initialize',
'args' => [
[
'type' => $settings['id'],
'url' => Url::fromRoute('ckeditor_mentions.ajax_callback', $urlParams)->setAbsolute()->toString(),
'marker' => $settings['marker'],
'removeMarker' => $settings['removeMarker'],
],
],
'invoke' => TRUE,
],
],
'itemRenderer' => [
'func' => [
'name' => 'CKEditor5.drupalMention.MentionsAjax.itemRender',
],
],
'minimumCharacters' => $settings['charcount'],
'drupalMentionsType' => $settings['id'],
'dropdownLimit' => $settings['dropdownLimit'],
];
}
if (!$options) {
return [];
}
return ['mention' => $options];
}
}
