Commit ac1dc4bb authored by bnjmnm's avatar bnjmnm
Browse files

Issue #3259593 by hooroomoo, Dom., Wim Leers, lauriii: Alignment being...

Issue #3259593 by hooroomoo, Dom., Wim Leers, lauriii: Alignment being available as separate buttons AND in dropdown is confusing
parent 3070c83b
......@@ -391,7 +391,7 @@ ckeditor5_horizontalLine:
- <hr>
ckeditor5_alignment:
ckeditor5: &alignment_ckeditor5_section
ckeditor5:
plugins: [alignment.Alignment]
config:
# @see core/modules/system/css/components/align.module.css
......@@ -405,60 +405,17 @@ ckeditor5_alignment:
className: text-align-right
- name: justify
className: text-align-justify
drupal: &alignment_drupal_section
drupal:
label: Alignment
library: core/ckeditor5.alignment
admin_library: ckeditor5/admin.alignment
class: Drupal\ckeditor5\Plugin\CKEditor5Plugin\Alignment
toolbar_items:
alignment:
label: Text alignment
elements:
- <$text-container class="text-align-left text-align-center text-align-right text-align-justify">
ckeditor5_alignment.left:
ckeditor5: *alignment_ckeditor5_section
drupal:
label: Align left
toolbar_items:
"alignment:left":
label: Align left
elements:
- <$text-container class="text-align-left">
<<: *alignment_drupal_section
ckeditor5_alignment.center:
ckeditor5: *alignment_ckeditor5_section
drupal:
label: Align center
toolbar_items:
"alignment:center":
label: Align center
elements:
- <$text-container class="text-align-center">
<<: *alignment_drupal_section
ckeditor5_alignment.right:
ckeditor5: *alignment_ckeditor5_section
drupal:
label: Align right
toolbar_items:
"alignment:right":
label: Align right
elements:
- <$text-container class="text-align-right">
<<: *alignment_drupal_section
ckeditor5_alignment.justify:
ckeditor5: *alignment_ckeditor5_section
drupal:
label: Justify
toolbar_items:
"alignment:justify":
label: Justify
elements:
- <$text-container class="text-align-justify">
<<: *alignment_drupal_section
ckeditor5_removeFormat:
ckeditor5:
plugins: [removeFormat.RemoveFormat]
......
<?php
/**
* @file
* Post update functions for CKEditor 5.
*/
use Drupal\Core\Config\Entity\ConfigEntityUpdater;
use Drupal\editor\Entity\Editor;
/**
* Updates if an already migrated CKEditor 5 configuration for text formats
* has alignment shown as individual buttons instead of a dropdown.
*/
function ckeditor5_post_update_alignment_buttons(&$sandbox = []) {
$config_entity_updater = \Drupal::classResolver(ConfigEntityUpdater::class);
$callback = function (Editor $editor) {
// Only try to update editors using CKEditor 5.
if ($editor->getEditor() !== 'ckeditor5') {
return FALSE;
}
$needs_update = FALSE;
// Only update if the editor is using the non-dropdown buttons.
$settings = $editor->getSettings();
$old_alignment_buttons_to_types = [
'alignment:left' => 'left',
'alignment:right' => 'right',
'alignment:center' => 'center',
'alignment:justify' => 'justify',
];
if (is_array($settings['toolbar']['items'])) {
foreach ($old_alignment_buttons_to_types as $button => $type) {
if (in_array($button, $settings['toolbar']['items'], TRUE)) {
$settings['toolbar']['items'] = array_values(array_diff($settings['toolbar']['items'], [$button]));
$settings['plugins']['ckeditor5_alignment']['enabled_alignments'][] = $type;
if (!in_array('alignment', $settings['toolbar']['items'], TRUE)) {
$settings['toolbar']['items'][] = 'alignment';
}
// Flag this display as needing to be updated.
$needs_update = TRUE;
}
}
}
if ($needs_update) {
$editor->setSettings($settings);
}
return $needs_update;
};
$config_entity_updater->update($sandbox, 'editor', $callback);
}
......@@ -87,6 +87,27 @@ ckeditor5.plugin.ckeditor5_sourceEditing:
SourceEditingRedundantTags: []
SourceEditingPreventSelfXssConstraint: []
# Plugin \Drupal\ckeditor5\Plugin\CKEditor5Plugin\Alignment
ckeditor5.plugin.ckeditor5_alignment:
type: mapping
label: Alignments
mapping:
enabled_alignments:
type: sequence
label: 'Enabled Alignments'
constraints:
NotBlank:
message: "Enable at least one alignment, otherwise disable the Alignment button."
sequence:
type: string
label: 'Alignment type'
constraints:
Choice:
- left
- center
- right
- justify
# Plugin \Drupal\ckeditor5\Plugin\CKEditor5Plugin\ListPlugin
ckeditor5.plugin.ckeditor5_list:
type: mapping
......
......@@ -59,6 +59,7 @@
* },
* cke5_plugin_elements_subset_configuration = {
* "ckeditor5_heading",
* "ckeditor5_alignment",
* "ckeditor5_list",
* "media_media",
* }
......@@ -73,6 +74,7 @@ class Core extends PluginBase implements CKEditor4To5UpgradePluginInterface {
* {@inheritdoc}
*/
public function mapCKEditor4ToolbarButtonToCKEditor5ToolbarItem(string $cke4_button, HTMLRestrictions $text_format_html_restrictions): ?array {
static $alignment_mapped;
switch ($cke4_button) {
// @see \Drupal\ckeditor\Plugin\CKEditorPlugin\DrupalImage
case 'DrupalImage':
......@@ -103,16 +105,14 @@ public function mapCKEditor4ToolbarButtonToCKEditor5ToolbarItem(string $cke4_but
return ['blockQuote'];
case 'JustifyLeft':
return ["alignment:left"];
case 'JustifyCenter':
return ["alignment:center"];
case 'JustifyRight':
return ["alignment:right"];
case 'JustifyBlock':
return ["alignment:justify"];
if (!isset($alignment_mapped)) {
$alignment_mapped = TRUE;
return ['alignment'];
}
return NULL;
case 'HorizontalRule':
return ['horizontalLine'];
......@@ -228,6 +228,37 @@ public function computeCKEditor5PluginSubsetConfiguration(string $cke5_plugin_id
}
return $configuration;
case 'ckeditor5_alignment':
$alignment_classes_to_types = [
'text-align-left' => 'left',
'text-align-right' => 'right',
'text-align-center' => 'center',
'text-align-justify' => 'justify',
];
$restrictions = $text_format->getHtmlRestrictions();
if ($restrictions === FALSE) {
// The default is to allow all alignments. This makes sense when there
// are no restrictions.
// @see \Drupal\ckeditor5\Plugin\CKEditor5Plugin\Alignment::DEFAULT_CONFIGURATION
return NULL;
}
// Otherwise, enable alignment types based on the provided restrictions.
// I.e. if a tag is found with a text-align-{alignment type} class,
// activate that alignment type.
$configuration = [];
foreach ($restrictions['allowed'] as $tag) {
$classes = isset($tag['class']) && is_array($tag['class']) ? $tag['class'] : [];
foreach (array_keys($classes) as $class) {
if (isset($alignment_classes_to_types[$class])) {
$configuration['enabled_alignments'][] = $alignment_classes_to_types[$class];
}
}
}
if (isset($configuration['enabled_alignments'])) {
$configuration['enabled_alignments'] = array_unique($configuration['enabled_alignments']);
}
return $configuration;
case 'ckeditor5_list':
$restrictions = $text_format->getHtmlRestrictions();
if ($restrictions === FALSE) {
......
<?php
declare(strict_types=1);
namespace Drupal\ckeditor5\Plugin\CKEditor5Plugin;
use Drupal\ckeditor5\Plugin\CKEditor5PluginConfigurableTrait;
use Drupal\ckeditor5\Plugin\CKEditor5PluginDefault;
use Drupal\ckeditor5\Plugin\CKEditor5PluginConfigurableInterface;
use Drupal\ckeditor5\Plugin\CKEditor5PluginElementsSubsetInterface;
use Drupal\Core\Form\FormStateInterface;
use Drupal\editor\EditorInterface;
use Drupal\ckeditor5\HTMLRestrictions;
/**
* CKEditor 5 Alignment plugin.
*
* @internal
* Plugin classes are internal.
*/
class Alignment extends CKEditor5PluginDefault implements CKEditor5PluginConfigurableInterface, CKEditor5PluginElementsSubsetInterface {
use CKEditor5PluginConfigurableTrait;
/**
* The default configuration for this plugin.
*
* @var string[][]
*/
const DEFAULT_CONFIGURATION = [
'enabled_alignments' => [
'left',
'center',
'right',
'justify',
],
];
/**
* {@inheritdoc}
*/
public function defaultConfiguration() {
return static::DEFAULT_CONFIGURATION;
}
/**
* {@inheritdoc}
*
* Form for choosing which alignment types are available.
*/
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$form['enabled_alignments'] = [
'#type' => 'fieldset',
'#title' => $this->t('Enabled Alignments'),
'#description' => $this->t('These are the alignment types that will appear in the alignment dropdown.'),
];
foreach ($this->getPluginDefinition()->getCKEditor5Config()['alignment']['options'] as $alignment_option) {
$name = $alignment_option['name'];
$form['enabled_alignments'][$name] = [
'#type' => 'checkbox',
'#title' => $this->t($name),
'#return_value' => $name,
'#default_value' => in_array($name, $this->configuration['enabled_alignments'], TRUE) ? $name : NULL,
];
}
return $form;
}
/**
* {@inheritdoc}
*/
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
// Match the config schema structure at ckeditor5.plugin.ckeditor5_alignment.
$form_value = $form_state->getValue('enabled_alignments');
$config_value = array_values(array_filter($form_value));
$form_state->setValue('enabled_alignments', $config_value);
}
/**
* {@inheritdoc}
*/
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$this->configuration['enabled_alignments'] = $form_state->getValue('enabled_alignments');
}
/**
* {@inheritdoc}
*
* Filters the alignment options to those chosen in editor config.
*/
public function getDynamicPluginConfig(array $static_plugin_config, EditorInterface $editor): array {
$enabled_alignments = $this->configuration['enabled_alignments'];
$all_alignment_options = $static_plugin_config['alignment']['options'];
$configured_alignment_options = array_filter($all_alignment_options, function ($option) use ($enabled_alignments) {
return in_array($option['name'], $enabled_alignments, TRUE);
});
return [
'alignment' => [
'options' => array_values($configured_alignment_options),
],
];
}
/**
* {@inheritdoc}
*/
public function getElementsSubset(): array {
$enabled_alignments = $this->configuration['enabled_alignments'];
$plugin_definition = $this->getPluginDefinition();
$all_elements = $plugin_definition->getElements();
$subset = HTMLRestrictions::fromString(implode($all_elements));
foreach ($plugin_definition->getCKEditor5Config()['alignment']['options'] as $configured_alignment) {
if (!in_array($configured_alignment['name'], $enabled_alignments, TRUE)) {
$element_string = '<$text-container class=' . '"' . $configured_alignment["className"] . '"' . '>';
$subset = $subset->diff(HTMLRestrictions::fromString($element_string));
}
}
return $subset->toCKEditor5ElementsArray();
}
}
<?php
/**
* @file
* Test fixture.
*/
use Drupal\Core\Database\Database;
use Drupal\Core\Serialization\Yaml;
$connection = Database::getConnection();
// Update core.extension.
$extensions = $connection->select('config')
->fields('config', ['data'])
->condition('collection', '')
->condition('name', 'core.extension')
->execute()
->fetchField();
$extensions = unserialize($extensions);
$extensions['module']['ckeditor5'] = 0;
$connection->update('config')
->fields(['data' => serialize($extensions)])
->condition('collection', '')
->condition('name', 'core.extension')
->execute();
$test_format_format = Yaml::decode(file_get_contents(__DIR__ . '/filter.format.test_format.yml'));
$connection->insert('config')
->fields([
'collection',
'name',
'data',
])
->values([
'collection' => '',
'name' => 'filter.format.test_format',
'data' => serialize($test_format_format),
])
->execute();
$test_format_editor = Yaml::decode(file_get_contents(__DIR__ . '/editor.editor.test_format.yml'));
$connection->insert('config')
->fields([
'collection',
'name',
'data',
])
->values([
'collection' => '',
'name' => 'editor.editor.test_format',
'data' => serialize($test_format_editor),
])
->execute();
uuid: f962b8c7-4c74-4100-b6de-08e6a65ff43d
langcode: en
status: true
dependencies:
config:
- filter.format.test_format
module:
- ckeditor5
format: test_format
editor: ckeditor5
settings:
toolbar:
items:
- link
- bold
- italic
- 'alignment:center'
- sourceEditing
plugins:
ckeditor5_sourceEditing:
allowed_tags: { }
image_upload: { }
uuid: 343a36d6-5852-45f5-b4de-437551cb9caf
langcode: en
status: true
dependencies: { }
name: 'Test format'
format: test_format
weight: 0
filters:
filter_html:
id: filter_html
provider: filter
status: true
weight: -10
settings:
allowed_html: '<br> <p class="text-align-center"> <strong> <em> <a href>'
filter_html_help: true
filter_html_nofollow: false
<?php
namespace Drupal\Tests\ckeditor5\Functional\Update;
use Drupal\editor\Entity\Editor;
use Drupal\FunctionalTests\Update\UpdatePathTestBase;
use Drupal\Tests\ckeditor5\Traits\CKEditor5TestTrait;
/**
* Tests the update path for CKEditor 5 alignment.
*
* @group Update
*/
class CKEditor5UpdateAlignmentTest extends UpdatePathTestBase {
use CKEditor5TestTrait;
/**
* {@inheritdoc}
*/
protected $defaultTheme = 'stark';
/**
* {@inheritdoc}
*/
protected function setDatabaseDumpFiles() {
$this->databaseDumpFiles = [
__DIR__ . '/../../../../../system/tests/fixtures/update/drupal-9.3.0.filled.standard.php.gz',
__DIR__ . '/../../../fixtures/update/ckeditor5-3259593.php',
];
}
/**
* Tests that CKEditor 5 alignment configurations that are individual buttons
* are updated to be in dropdown form in the toolbar.
*/
public function testUpdateAlignmentButtons() {
$editor = Editor::load('test_format');
$settings = $editor->getSettings();
$this->assertContains('alignment:center', $settings['toolbar']['items']);
$this->runUpdates();
$expected_toolbar_items = [
'link',
'bold',
'italic',
'sourceEditing',
'alignment',
];
$expected_alignment_plugin = [
'enabled_alignments' => [
'center',
],
];
$editor = Editor::load('test_format');
$settings = $editor->getSettings();
$this->assertEquals($expected_toolbar_items, $settings['toolbar']['items']);
$this->assertEquals($expected_alignment_plugin, $settings['plugins']['ckeditor5_alignment']);
}
}
......@@ -1119,11 +1119,11 @@ public function testEnabledPlugins() {
// Case 7: GHS is enabled for other text editors if they are using a
// CKEditor 5 plugin that uses wildcard tags.
$settings['toolbar']['items'][] = 'alignment:center';
$settings['toolbar']['items'][] = 'alignment';
$editor->setSettings($settings);
$plugin_ids = array_keys($this->manager->getEnabledDefinitions($editor));
$expected_plugins = array_merge($expected_plugins, [
'ckeditor5_alignment.center',
'ckeditor5_alignment',
'ckeditor5_wildcardHtmlSupport',
]);
sort($expected_plugins);
......
......@@ -71,6 +71,14 @@ public function testDefaults() {
'reversed' => TRUE,
'startIndex' => TRUE,
],
'ckeditor5_alignment' => [
'enabled_alignments' => [
0 => 'left',
1 => 'center',
2 => 'right',
3 => 'justify',
],
],
'ckeditor5_imageResize' => [
'allow_resize' => TRUE,
],
......
......@@ -752,14 +752,19 @@ public function provider() {
'toolbar' => [
'items' => array_merge(
array_slice($basic_html_test_case['expected_ckeditor5_settings']['toolbar']['items'], 0, -1),
[
'alignment:center',
'alignment:justify',
],
['alignment'],
array_slice($basic_html_test_case['expected_ckeditor5_settings']['toolbar']['items'], -1)
),
],
'plugins' => $basic_html_test_case['expected_ckeditor5_settings']['plugins'],
'plugins' => array_merge(
array_slice($basic_html_test_case['expected_ckeditor5_settings']['plugins'], 0, 1),
[
'ckeditor5_alignment' => [
'enabled_alignments' => ['center', 'justify'],
],
],
array_slice($basic_html_test_case['expected_ckeditor5_settings']['plugins'], 1),
),
],
'expected_superset' => implode(' ', [
// Note that aligning left and right is being added, on top of what the
......@@ -779,7 +784,7 @@ public function provider() {
'expected_fundamental_compatibility_violations' => $basic_html_test_case['expected_fundamental_compatibility_violations'],
'expected_messages' => array_merge_recursive($basic_html_test_case['expected_messages'], [
'status' => [
'The following plugins were enabled to support specific attributes that are allowed by this text format: <em class="placeholder">Align center ( for tag: &lt;p&gt; to support: class with value(s): text-align-center), Justify ( for tag: &lt;p&gt; to support: class with value(s): text-align-justify)</em>.',
'The following plugins were enabled to support specific attributes that are allowed by this text format: <em class="placeholder">Alignment ( for tag: &lt;p&gt; to support: class with value(s): text-align-center, text-align-justify)</em>.',
'This format\'s HTML filters includes plugins that support the following tags, but not some of their attributes. To ensure these attributes remain supported by this text format, the following were added to the Source Editing plugin\'s <em>Manually editable HTML tags</em>: &lt;a hreflang&gt; &lt;blockquote cite&gt; &lt;ul type&gt; &lt;ol type&gt; &lt;h2 id&gt; &lt;h3 id&gt; &lt;h4 id&gt; &lt;h5 id&gt; &lt;h6 id&gt;.',
],
]),
......
......@@ -745,7 +745,7 @@ public function providerPair(): array {
'settings.plugins.ckeditor5_sourceEditing.allowed_tags.1' => 'The following tag(s) are already supported by available plugins and should not be added to the Source Editing "Manually editable HTML tags" field. Instead, enable the following plugins to support these tags: <em class="placeholder">Table (&lt;table&gt;)</em>.',
'settings.plugins.ckeditor5_sourceEditing.allowed_tags.3' => 'The following attribute(s) are already supported by enabled plugins and should not be added to the Source Editing "Manually editable HTML tags" field: <em class="placeholder">Language (&lt;span lang&gt;)</em>.',
'settings.plugins.ckeditor5_sourceEditing.allowed_tags.5' => 'The following tag(s) are already supported by available plugins and should not be added to the Source Editing "Manually editable HTML tags" field. Instead, enable the following plugins to support these tags: <em class="placeholder">Code Block (&lt;code class=&quot;language-*&quot;&gt;)</em>.',
'settings.plugins.ckeditor5_sourceEditing.allowed_tags.6' => 'The following attribute(s) are already supported by available plugins and should not be added to the Source Editing "Manually editable HTML tags" field. Instead, enable the following plugins to support these attributes: <em class="placeholder">Alignment (&lt;h2 class=&quot;text-align-center&quot;&gt;), Align center (&lt;h2 class=&quot;text-align-center&quot;&gt;)</em>.',
'settings.plugins.ckeditor5_sourceEditing.allowed_tags.6' => 'The following attribute(s) are already supported by available plugins and should not be added to the Source Editing "Manually editable HTML tags" field. Instead, enable the following plugins to support these attributes: <em class="placeholder">Alignment (&lt;h2 class=&quot;text-align-center&quot;&gt;)</em>.',
],
];
$data['INVALID some invalid Source Editable tags provided by plugin and another available in a not enabled plugin'] = [
......