View source
<?php
namespace Drupal\ckeditor\Plugin\Editor;
use Drupal\Core\Extension\ModuleHandlerInterface;
use Drupal\ckeditor\CKEditorPluginManager;
use Drupal\Core\Form\FormStateInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Render\Element;
use Drupal\Core\Render\RendererInterface;
use Drupal\Core\State\StateInterface;
use Drupal\editor\Plugin\EditorBase;
use Drupal\Core\Plugin\ContainerFactoryPluginInterface;
use Drupal\editor\Entity\Editor;
use Symfony\Component\DependencyInjection\ContainerInterface;
class CKEditor extends EditorBase implements ContainerFactoryPluginInterface {
protected $moduleHandler;
protected $languageManager;
protected $ckeditorPluginManager;
protected $renderer;
protected $state;
public function __construct(array $configuration, $plugin_id, $plugin_definition, CKEditorPluginManager $ckeditor_plugin_manager, ModuleHandlerInterface $module_handler, LanguageManagerInterface $language_manager, RendererInterface $renderer, StateInterface $state = NULL) {
parent::__construct($configuration, $plugin_id, $plugin_definition);
$this->ckeditorPluginManager = $ckeditor_plugin_manager;
$this->moduleHandler = $module_handler;
$this->languageManager = $language_manager;
$this->renderer = $renderer;
if ($state === NULL) {
@trigger_error('Calling CKEditor::__construct() without the $state argument is deprecated in drupal:8.8.0. The $state argument is required in drupal:9.0.0. See https://www.drupal.org/node/3075102.', E_USER_DEPRECATED);
$state = \Drupal::service('state');
}
$this->state = $state;
}
public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) {
return new static($configuration, $plugin_id, $plugin_definition, $container
->get('plugin.manager.ckeditor.plugin'), $container
->get('module_handler'), $container
->get('language_manager'), $container
->get('renderer'), $container
->get('state'));
}
public function getDefaultSettings() {
return [
'toolbar' => [
'rows' => [
[
[
'name' => $this
->t('Formatting'),
'items' => [
'Bold',
'Italic',
],
],
[
'name' => $this
->t('Links'),
'items' => [
'DrupalLink',
'DrupalUnlink',
],
],
[
'name' => $this
->t('Lists'),
'items' => [
'BulletedList',
'NumberedList',
],
],
[
'name' => $this
->t('Media'),
'items' => [
'Blockquote',
'DrupalImage',
],
],
[
'name' => $this
->t('Tools'),
'items' => [
'Source',
],
],
],
],
],
'plugins' => [
'language' => [
'language_list' => 'un',
],
],
];
}
public function buildConfigurationForm(array $form, FormStateInterface $form_state) {
$editor = $form_state
->get('editor');
$settings = $editor
->getSettings();
$ckeditor_settings_toolbar = [
'#theme' => 'ckeditor_settings_toolbar',
'#editor' => $editor,
'#plugins' => $this->ckeditorPluginManager
->getButtons(),
];
$form['toolbar'] = [
'#type' => 'container',
'#attached' => [
'library' => [
'ckeditor/drupal.ckeditor.admin',
],
'drupalSettings' => [
'ckeditor' => [
'toolbarAdmin' => (string) $this->renderer
->renderPlain($ckeditor_settings_toolbar),
],
],
],
'#attributes' => [
'class' => [
'ckeditor-toolbar-configuration',
],
],
];
$form['toolbar']['button_groups'] = [
'#type' => 'textarea',
'#title' => $this
->t('Toolbar buttons'),
'#default_value' => json_encode($settings['toolbar']['rows']),
'#attributes' => [
'class' => [
'ckeditor-toolbar-textarea',
],
],
];
$form['plugin_settings'] = [
'#type' => 'vertical_tabs',
'#title' => $this
->t('CKEditor plugin settings'),
'#attributes' => [
'id' => 'ckeditor-plugin-settings',
],
];
$this->ckeditorPluginManager
->injectPluginSettingsForm($form, $form_state, $editor);
if (count(Element::children($form['plugins'])) === 0) {
unset($form['plugins']);
unset($form['plugin_settings']);
}
$plugins = array_keys($this->ckeditorPluginManager
->getDefinitions());
$all_external_plugins = [];
foreach ($plugins as $plugin_id) {
$plugin = $this->ckeditorPluginManager
->createInstance($plugin_id);
if (!$plugin
->isInternal()) {
$all_external_plugins[$plugin_id] = $plugin
->getFile();
}
}
$all_buttons = array_reduce($this->ckeditorPluginManager
->getButtons(), function ($result, $item) {
return array_merge($result, array_keys($item));
}, []);
$fake_editor = Editor::create([
'format' => $editor
->id(),
'editor' => 'ckeditor',
'settings' => [
'toolbar' => [
'rows' => [
0 => [
0 => [
'name' => 'All existing buttons',
'items' => $all_buttons,
],
],
],
],
'plugins' => $settings['plugins'],
],
]);
$config = $this
->getJSSettings($fake_editor);
unset($config['allowedContent']);
$form['hidden_ckeditor'] = [
'#markup' => '<div id="ckeditor-hidden" class="hidden"></div>',
'#attached' => [
'drupalSettings' => [
'ckeditor' => [
'hiddenCKEditorConfig' => $config,
],
],
],
];
return $form;
}
public function validateConfigurationForm(array &$form, FormStateInterface $form_state) {
}
public function submitConfigurationForm(array &$form, FormStateInterface $form_state) {
$form_state
->setValue([
'toolbar',
'rows',
], json_decode($form_state
->getValue([
'toolbar',
'button_groups',
]), TRUE));
$form_state
->unsetValue([
'toolbar',
'button_groups',
]);
if ($form_state
->hasValue('plugins')) {
$form_state
->unsetValue('plugin_settings');
}
}
public function getJSSettings(Editor $editor) {
$settings = [];
$enabled_plugins = array_keys($this->ckeditorPluginManager
->getEnabledPluginFiles($editor, TRUE));
foreach ($enabled_plugins as $plugin_id) {
$plugin = $this->ckeditorPluginManager
->createInstance($plugin_id);
$settings += $plugin
->getConfig($editor);
}
$display_langcode = 'en';
if ($this->moduleHandler
->moduleExists('locale')) {
$ckeditor_langcodes = $this
->getLangcodes();
$language_interface = $this->languageManager
->getCurrentLanguage();
if (isset($ckeditor_langcodes[$language_interface
->getId()])) {
$display_langcode = $ckeditor_langcodes[$language_interface
->getId()];
}
}
$external_plugin_files = $this->ckeditorPluginManager
->getEnabledPluginFiles($editor);
$settings += [
'toolbar' => $this
->buildToolbarJSSetting($editor),
'contentsCss' => $this
->buildContentsCssJSSetting($editor),
'extraPlugins' => implode(',', array_keys($external_plugin_files)),
'language' => $display_langcode,
'stylesSet' => FALSE,
];
$root_relative_file_url = function ($uri) {
return file_url_transform_relative(file_create_url($uri));
};
$settings += [
'drupalExternalPlugins' => array_map($root_relative_file_url, $external_plugin_files),
];
if ($this->moduleHandler
->moduleExists('locale')) {
locale_js_translate(array_values($external_plugin_files));
}
ksort($settings);
return $settings;
}
public function getLangcodes() {
$langcode_cache = \Drupal::cache()
->get('ckeditor.langcodes');
if (!empty($langcode_cache)) {
$langcodes = $langcode_cache->data;
}
if (empty($langcodes)) {
$langcodes = [];
$files = scandir('core/assets/vendor/ckeditor/lang');
foreach ($files as $file) {
if ($file[0] !== '.' && preg_match('/\\.js$/', $file)) {
$langcode = basename($file, '.js');
$langcodes[$langcode] = $langcode;
}
}
\Drupal::cache()
->set('ckeditor.langcodes', $langcodes);
}
$language_mappings = $this->moduleHandler
->moduleExists('language') ? language_get_browser_drupal_langcode_mappings() : [];
foreach ($langcodes as $langcode) {
if (isset($language_mappings[$langcode]) && !isset($langcodes[$language_mappings[$langcode]])) {
$langcodes[$language_mappings[$langcode]] = $langcode;
unset($langcodes[$langcode]);
}
}
return $langcodes;
}
public function getLibraries(Editor $editor) {
$libraries = [
'ckeditor/drupal.ckeditor',
];
$enabled_plugins = array_keys($this->ckeditorPluginManager
->getEnabledPluginFiles($editor));
foreach ($enabled_plugins as $plugin_id) {
$plugin = $this->ckeditorPluginManager
->createInstance($plugin_id);
$additional_libraries = array_diff($plugin
->getLibraries($editor), $libraries);
$libraries = array_merge($libraries, $additional_libraries);
}
return $libraries;
}
public function buildToolbarJSSetting(Editor $editor) {
$toolbar = [];
$settings = $editor
->getSettings();
foreach ($settings['toolbar']['rows'] as $row) {
foreach ($row as $group) {
$toolbar[] = $group;
}
$toolbar[] = '/';
}
return $toolbar;
}
public function buildContentsCssJSSetting(Editor $editor) {
$css = [
drupal_get_path('module', 'ckeditor') . '/css/ckeditor-iframe.css',
drupal_get_path('module', 'system') . '/css/components/align.module.css',
];
$this->moduleHandler
->alter('ckeditor_css', $css, $editor);
$plugins_css = array_reduce($this->ckeditorPluginManager
->getCssFiles($editor), function ($result, $item) {
return array_merge($result, array_values($item));
}, []);
$css = array_merge($css, $plugins_css);
$css = array_merge($css, _ckeditor_theme_css());
$query_string = $this->state
->get('system.css_js_query_string', '0');
$css = array_map(function ($item) use ($query_string) {
$query_string_separator = strpos($item, '?') !== FALSE ? '&' : '?';
return $item . $query_string_separator . $query_string;
}, $css);
$css = array_map('file_create_url', $css);
$css = array_map('file_url_transform_relative', $css);
return array_values($css);
}
}