Chris@0: alterInfo('ckeditor_plugin_info'); Chris@0: $this->setCacheBackend($cache_backend, 'ckeditor_plugins'); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Retrieves enabled plugins' files, keyed by plugin ID. Chris@0: * Chris@0: * For CKEditor plugins that implement: Chris@0: * - CKEditorPluginButtonsInterface, not CKEditorPluginContextualInterface, Chris@0: * a plugin is enabled if at least one of its buttons is in the toolbar; Chris@0: * - CKEditorPluginContextualInterface, not CKEditorPluginButtonsInterface, Chris@0: * a plugin is enabled if its isEnabled() method returns TRUE Chris@0: * - both of these interfaces, a plugin is enabled if either is the case. Chris@0: * Chris@0: * Internal plugins (those that are part of the bundled build of CKEditor) are Chris@0: * excluded by default, since they are loaded implicitly. If you need to know Chris@0: * even implicitly loaded (i.e. internal) plugins, then set the optional Chris@0: * second parameter. Chris@0: * Chris@0: * @param \Drupal\editor\Entity\Editor $editor Chris@0: * A configured text editor object. Chris@0: * @param bool $include_internal_plugins Chris@0: * Defaults to FALSE. When set to TRUE, plugins whose isInternal() method Chris@0: * returns TRUE will also be included. Chris@0: * @return array Chris@0: * A list of the enabled CKEditor plugins, with the plugin IDs as keys and Chris@0: * the Drupal root-relative plugin files as values. Chris@0: * For internal plugins, the value is NULL. Chris@0: */ Chris@0: public function getEnabledPluginFiles(Editor $editor, $include_internal_plugins = FALSE) { Chris@0: $plugins = array_keys($this->getDefinitions()); Chris@0: $toolbar_buttons = $this->getEnabledButtons($editor); Chris@0: $enabled_plugins = []; Chris@0: $additional_plugins = []; Chris@0: Chris@0: foreach ($plugins as $plugin_id) { Chris@0: $plugin = $this->createInstance($plugin_id); Chris@0: Chris@0: if (!$include_internal_plugins && $plugin->isInternal()) { Chris@0: continue; Chris@0: } Chris@0: Chris@0: $enabled = FALSE; Chris@0: // Enable this plugin if it provides a button that has been enabled. Chris@0: if ($plugin instanceof CKEditorPluginButtonsInterface) { Chris@0: $plugin_buttons = array_keys($plugin->getButtons()); Chris@0: $enabled = (count(array_intersect($toolbar_buttons, $plugin_buttons)) > 0); Chris@0: } Chris@0: // Otherwise enable this plugin if it declares itself as enabled. Chris@0: if (!$enabled && $plugin instanceof CKEditorPluginContextualInterface) { Chris@0: $enabled = $plugin->isEnabled($editor); Chris@0: } Chris@0: Chris@0: if ($enabled) { Chris@0: $enabled_plugins[$plugin_id] = ($plugin->isInternal()) ? NULL : $plugin->getFile(); Chris@0: // Check if this plugin has dependencies that also need to be enabled. Chris@0: $additional_plugins = array_merge($additional_plugins, array_diff($plugin->getDependencies($editor), $additional_plugins)); Chris@0: } Chris@0: } Chris@0: Chris@0: // Add the list of dependent plugins. Chris@0: foreach ($additional_plugins as $plugin_id) { Chris@0: $plugin = $this->createInstance($plugin_id); Chris@0: $enabled_plugins[$plugin_id] = ($plugin->isInternal()) ? NULL : $plugin->getFile(); Chris@0: } Chris@0: Chris@0: // Always return plugins in the same order. Chris@0: asort($enabled_plugins); Chris@0: Chris@0: return $enabled_plugins; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Gets the enabled toolbar buttons in the given text editor instance. Chris@0: * Chris@0: * @param \Drupal\editor\Entity\Editor $editor Chris@0: * A configured text editor object. Chris@0: * Chris@0: * @return string[] Chris@0: * A list of the toolbar buttons enabled in the given text editor instance. Chris@0: */ Chris@0: public static function getEnabledButtons(Editor $editor) { Chris@0: $toolbar_rows = []; Chris@0: $settings = $editor->getSettings(); Chris@0: foreach ($settings['toolbar']['rows'] as $row_number => $row) { Chris@0: $toolbar_rows[] = array_reduce($settings['toolbar']['rows'][$row_number], function (&$result, $button_group) { Chris@0: return array_merge($result, $button_group['items']); Chris@0: }, []); Chris@0: } Chris@0: return array_unique(NestedArray::mergeDeepArray($toolbar_rows)); Chris@0: } Chris@0: Chris@0: /** Chris@0: * Retrieves all available CKEditor buttons, keyed by plugin ID. Chris@0: * Chris@0: * @return array Chris@0: * All available CKEditor buttons, with plugin IDs as keys and button Chris@0: * metadata (as implemented by getButtons()) as values. Chris@0: * Chris@0: * @see \Drupal\ckeditor\CKEditorPluginButtonsInterface::getButtons() Chris@0: */ Chris@0: public function getButtons() { Chris@0: $plugins = array_keys($this->getDefinitions()); Chris@0: $buttons_plugins = []; Chris@0: Chris@0: foreach ($plugins as $plugin_id) { Chris@0: $plugin = $this->createInstance($plugin_id); Chris@0: if ($plugin instanceof CKEditorPluginButtonsInterface) { Chris@0: $buttons_plugins[$plugin_id] = $plugin->getButtons(); Chris@0: } Chris@0: } Chris@0: Chris@0: return $buttons_plugins; Chris@0: } Chris@0: Chris@0: /** Chris@0: * Injects the CKEditor plugins settings forms as a vertical tabs subform. Chris@0: * Chris@0: * @param array &$form Chris@0: * A reference to an associative array containing the structure of the form. Chris@0: * @param \Drupal\Core\Form\FormStateInterface $form_state Chris@0: * The current state of the form. Chris@0: * @param \Drupal\editor\Entity\Editor $editor Chris@0: * A configured text editor object. Chris@0: */ Chris@0: public function injectPluginSettingsForm(array &$form, FormStateInterface $form_state, Editor $editor) { Chris@0: $definitions = $this->getDefinitions(); Chris@0: Chris@0: foreach (array_keys($definitions) as $plugin_id) { Chris@0: $plugin = $this->createInstance($plugin_id); Chris@0: if ($plugin instanceof CKEditorPluginConfigurableInterface) { Chris@0: $plugin_settings_form = []; Chris@0: $form['plugins'][$plugin_id] = [ Chris@0: '#type' => 'details', Chris@0: '#title' => $definitions[$plugin_id]['label'], Chris@0: '#open' => TRUE, Chris@0: '#group' => 'editor][settings][plugin_settings', Chris@0: '#attributes' => [ Chris@0: 'data-ckeditor-plugin-id' => $plugin_id, Chris@0: ], Chris@0: ]; Chris@0: // Provide enough metadata for the drupal.ckeditor.admin library to Chris@0: // allow it to automatically show/hide the vertical tab containing the Chris@0: // settings for this plugin. Only do this if it's a CKEditor plugin that Chris@0: // just provides buttons, don't do this if it's a contextually enabled Chris@0: // CKEditor plugin. After all, in the latter case, we can't know when Chris@0: // its settings should be shown! Chris@0: if ($plugin instanceof CKEditorPluginButtonsInterface && !$plugin instanceof CKEditorPluginContextualInterface) { Chris@0: $form['plugins'][$plugin_id]['#attributes']['data-ckeditor-buttons'] = implode(' ', array_keys($plugin->getButtons())); Chris@0: } Chris@0: $form['plugins'][$plugin_id] += $plugin->settingsForm($plugin_settings_form, $form_state, $editor); Chris@0: } Chris@0: } Chris@0: } Chris@0: Chris@0: /** Chris@0: * Retrieves enabled plugins' iframe instance CSS files, keyed by plugin ID. Chris@0: * Chris@0: * @param \Drupal\editor\Entity\Editor $editor Chris@0: * A configured text editor object. Chris@0: * Chris@0: * @return string[] Chris@0: * Enabled plugins CKEditor CSS files, with plugin IDs as keys and CSS file Chris@0: * paths relative to the Drupal root (as implemented by getCssFiles()) as Chris@0: * values. Chris@0: * Chris@0: * @see \Drupal\ckeditor\CKEditorPluginCssInterface::getCssFiles() Chris@0: */ Chris@0: public function getCssFiles(Editor $editor) { Chris@0: $enabled_plugins = array_keys($this->getEnabledPluginFiles($editor, TRUE)); Chris@0: $css_files = []; Chris@0: Chris@0: foreach ($enabled_plugins as $plugin_id) { Chris@0: $plugin = $this->createInstance($plugin_id); Chris@0: if ($plugin instanceof CKEditorPluginCssInterface) { Chris@0: $css_files[$plugin_id] = $plugin->getCssFiles($editor); Chris@0: } Chris@0: } Chris@0: Chris@0: return $css_files; Chris@0: } Chris@0: Chris@0: }