Published:
Módulo ckeditor drupal Permalink
As vezes é muito útil injetar um botão nosso no ckeditor do Drupal, segue-se um exemplo de um botão customizado ao ser clicado abre um modal com ajax que recebe um texto e o injeta no corpo do texto. Isso em si não é nada útil, mas a possibilidade de interceptamos e fazermos qualquer modificação com esse botão.
Criando um módulo chamado ckeditor_generic com ckeditor_generic.info.yml:
name: CKEditor Button Generic Example
type: module
description: "CKEditor Button"
package: CKEditor
core: 8.x
core_version_requirement: ^8 || ^9
dependencies:
- drupal:ckeditor
O plugin que implementa CKEditorPluginBase
colocamos em src/Plugin/CKEditorPlugin/CkeditorGeneric.php
:
<?php
namespace Drupal\ckeditor_generic\Plugin\CKEditorPlugin;
use Drupal\ckeditor\CKEditorPluginBase;
use Drupal\editor\Entity\Editor;
/**
* Defines the "ckeditor_generic" plugin.
*
* @CKEditorPlugin(
* id = "ckeditor_generic",
* label = @Translation("CKEditor Button")
* )
*/
class CkeditorGeneric extends CKEditorPluginBase {
/**
* {@inheritdoc}
*/
public function getFile() {
return drupal_get_path('module', 'ckeditor_generic') . '/js/plugin.js';
}
/**
* {@inheritdoc}
*/
public function getConfig(Editor $editor) {
return array(
'dialog_title_insert' => $this->t('Insert a Text'),
);
}
/**
* Implements CKEditorPluginButtonsInterface::getButtons().
*/
public function getButtons() {
return array(
'ckeditor_generic_button' => array(
'label' => $this->t('Ckediton Button'),
'image' => drupal_get_path('module', 'ckeditor_generic') . '/images/icone.png',
),
);
}
}
em /images/icone.png coloque uma imagem qualquer para o ícone do seu botão e crie /js/plugin.js
por enquanto vazio.
Agora criemos um arquivo para o formulário em src/Form/CkeditorGenericDialog.php:
<?php
namespace Drupal\ckeditor_generic\Form;
use Drupal\Core\Form\FormBase;
use Drupal\Core\Form\FormStateInterface;
use Drupal\filter\Entity\FilterFormat;
use Drupal\Core\Ajax\AjaxResponse;
use Drupal\Core\Ajax\HtmlCommand;
use Drupal\editor\Ajax\EditorDialogSave;
use Drupal\Core\Ajax\CloseModalDialogCommand;
class CkeditorGenericDialog extends FormBase {
/**
* {@inheritdoc}
*/
public function getFormId() {
return 'editor_ckeditor_generic_dialog';
}
/**
* {@inheritdoc}
*
* @param \Drupal\filter\Entity\FilterFormat $filter_format
* The filter format for which this dialog corresponds.
*/
public function buildForm(array $form, FormStateInterface $form_state, FilterFormat $filter_format = NULL) {
$user_input = $form_state->getUserInput();
$input = isset($user_input['editor_object']) ? $user_input['editor_object'] : array();
$form['#tree'] = TRUE;
$form['#attached']['library'][] = 'editor/drupal.editor.dialog';
$form['#attached']['library'][] = 'ckeditor_generic/ckeditor_generic.dialog';
$form['#prefix'] = '<div id="editor-ckeditor-generic-dialog-form">';
$form['#suffix'] = '</div>';
$form['attributes']['body'] = array(
'#type' => 'textarea',
'#title' => $this->t('Body'),
'#default_value' => isset($input['body']) ? $input['body'] : '',
'#size' => 50,
);
$form['actions'] = array(
'#type' => 'actions',
);
$form['actions']['save_modal'] = array(
'#type' => 'submit',
'#value' => $this->t('Insert'),
// No regular submit-handler. This form only works via JavaScript.
'#submit' => array(),
'#ajax' => array(
'callback' => '::submitForm',
'event' => 'click',
),
);
return $form;
}
/**
* {@inheritdoc}
*/
public function submitForm(array &$form, FormStateInterface $form_state) {
$response = new AjaxResponse();
if ($form_state->getErrors()) {
unset($form['#prefix'], $form['#suffix']);
$form['status_messages'] = [
'#type' => 'status_messages',
'#weight' => -10,
];
$response->addCommand(new HtmlCommand('#editor-ckeditor-generic-dialog-form', $form));
}
else {
$response->addCommand(new EditorDialogSave($form_state->getValues()));
$response->addCommand(new CloseModalDialogCommand());
}
return $response;
}
}
E definimos a rota correspondente do formulário, no caso ajax ckeditor_generic.routing.yml
:
ckeditor_generic.dialog:
path: '/ckeditor_generic/dialog'
defaults:
_form: '\Drupal\ckeditor_generic\Form\CkeditorGenericDialog'
_title: 'ckeditor_generic'
options:
_theme: ajax_base_page
requirements:
_permission: 'access in-place editing'
Vamos injetar código css/js tanto no modal quanto dentro do conteúdo inserido no ckeditor, assim implementemos ckeditor_generic.libraries.yml
:
ckeditor_generic:
version: VERSION
css:
theme:
css/ckeditor_generic.css: {}
ckeditor_generic.dialog:
version: VERSION
css:
theme:
css/dialog.css: {}
Em css/dialog.css eu injetei esse css:
#editor-ckeditor-generic-dialog-form .form-item-attributes-body {
clear: both;
background-color: yellow;
}
E em ckeditor_generic.css:
.ckeditor-generic{
background-color: red;
color: blue;
}
h1.ckeditor-generic-header {
color: green;
}
Claro, essas cores foram usada só para verificar se o código está chegando onde deveria estar chegando.
Por fim o plugin.js
que trata da ação do botão em si:
/**
* @file
* ckeditor_generic plugin.
*
* @ignore
*/
(function ($, Drupal, drupalSettings, CKEDITOR) {
'use strict';
CKEDITOR.plugins.add('ckeditor_generic', {
init: function (editor) {
editor.addCommand('ckeditor_generic', {
modes: {wysiwyg: 1},
canUndo: true,
exec: function (editor) {
// Prepare a save callback to be used upon saving the dialog.
var saveCallback = function (returnValues) {
editor.fire('saveSnapshot');
if (returnValues.attributes.body) {
var selection = editor.getSelection();
var range = selection.getRanges(1)[0];
if (range.collapsed) {
var values = returnValues.attributes;
var container = editor.document.createElement('div');
container.setAttribute('class', 'ckeditor-generic');
var header = editor.document.createElement('h1');
header.setAttribute('class', 'ckeditor-generic-header');
header.setHtml('parte de cima');
var body = editor.document.createElement('p');
body.setHtml(values.body);
container.append(header);
container.append(body);
editor.insertElement(container);
}
}
// Save snapshot for undo support.
editor.fire('saveSnapshot');
};
// Drupal.t() will not work inside CKEditor plugins because CKEditor
// loads the JavaScript file instead of Drupal. Pull translated
// strings from the plugin settings that are translated server-side.
var dialogSettings = {
title: editor.config.dialog_title_insert,
dialogClass: 'ckeditor_generic-dialog'
};
// Open the dialog for the edit form.
var existingValues = {};
Drupal.ckeditor.openDialog(editor, Drupal.url('ckeditor_generic/dialog'), existingValues, saveCallback, dialogSettings);
}
});
// Add button
if (editor.ui.addButton) {
editor.ui.addButton('ckeditor_generic_button', {
label: Drupal.t('Insert ckeditor_generic'),
command: 'ckeditor_generic',
icon: this.path + '../images/icone.png'
});
}
// If the "menu" plugin is loaded, register the menu items.
if (editor.addMenuItems) {
editor.addMenuItems({
ckeditor_generic: {
label: Drupal.t('ckeditor_generic'),
command: 'ckeditor_generic',
group: 'tools',
order: 1
}
});
}
}
});
})(jQuery, Drupal, drupalSettings, CKEDITOR);