Newer
Older

Angie Byron
committed
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
<?php
/**
* @file
* Adds bindings for client-side "text editors" to text formats.
*/
use Drupal\file\Plugin\Core\Entity\File;
use Drupal\editor\Plugin\Core\Entity\Editor;
use Drupal\Component\Utility\NestedArray;
/**
* Implements hook_help().
*/
function editor_help($path, $arg) {
switch ($path) {
case 'admin/help#editor':
$output = '';
$output .= '<h3>' . t('About') . '</h3>';
$output .= '<p>' . t('The Text Editor module provides a framework to extend the user interface on text fields that allow HTML input. Without Text Editor module, fields accept only text where formatting must be typed manually, such as entering a <code><strong></code> tag to make text bold or an <code><em></code> tag to italicize text. The Text Editor module allows these fields to be enhanced with rich text editors (WYSIWYGs) or toolbars, which make entering and formatting content easier. For more information, see the online handbook entry for <a href="@editor">Editor module</a>.', array('@editor' => 'http://drupal.org/documentation/modules/editor/')) . '</p>';
$output .= '<h3>' . t('Uses') . '</h3>';
$output .= '<dl>';
$output .= '<dt>' . t('Enabling or configuring a text editor') . '</dt>';
$output .= '<dd>' . t('The Text Editor module does not have its own configuration page. Instead it enhances existing configuration pages with additional options. Text editors are attached to individual text formats, which can be configured on the <a href="@formats">Text formats page</a>. Each text format may be associated with a single text editor. When entering content with that text format, the associated text editor will automatically be enabled.', array('@formats' => url('admin/config/content/formats'))) . '</dd>';
$output .= '<dt>' . t('Allowing a user to choose a text editor') . '</dt>';
$output .= '<dd>' . t('Because text editor configurations are bound to a text format, users with access to more than one text format may switch between available text editors by changing the text format for a field. For more information about text formats, see the <a href="@filter">Filter module help page</a>, which describes text formats in more detail.', array('@filter' => url('admin/help/filter'))) . '</dd>';
// @todo: Mention the availability of the built-in core WYSIWYG (CKEditor)
// when it becomes available. See http://drupal.org/node/1878344.
$output .= '<dt>' . t('Installing additional text editor libraries') . '</dt>';
$output .= '<dd>' . t('The Text Editor module does not provide any text editor libraries itself. Most installations of Drupal include a module that provides a text editor library which may be enabled on the <a href="@modules">Modules page</a>. Additional modules that provide text editor libraries may be <a href="@download">downloaded from Drupal.org</a>.', array('@modules' => url('admin/modules'), '@download' => 'http://drupal.org/search/site/wysiwyg%20module')) . '</dd>';
$output .= '</dl>';
return $output;
}
}
/**
* Implements hook_menu_alter().
*
* Rewrites the menu entries for filter module that relate to the configuration
* of text editors.
*/
function editor_menu_alter(&$items) {
$items['admin/config/content/formats']['title'] = 'Text formats and editors';
$items['admin/config/content/formats']['description'] = 'Configure how user-contributed content is filtered and formatted, as well as the text editor user interface (WYSIWYGs or toolbars).';
}
/**
* Implements hook_element_info().
*
* Extends the functionality of text_format elements (provided by Filter
* module), so that selecting a text format notifies a client-side text editor
* when it should be enabled or disabled.
*
* @see filter_element_info()
*/
function editor_element_info() {
$type['text_format'] = array(
'#pre_render' => array('editor_pre_render_format'),
);
return $type;
}
/**
* Implements hook_library_info().
*/
function editor_library_info() {
$path = drupal_get_path('module', 'editor');
$libraries['drupal.editor'] = array(
'title' => 'Text Editor',
'version' => VERSION,
'js' => array(
$path . '/js/editor.js' => array(),
),
'dependencies' => array(
array('system', 'jquery'),
array('system', 'drupal'),
array('system', 'drupalSettings'),
array('system', 'jquery.once'),
),
);

Dries Buytaert
committed
$libraries['edit.formattedTextEditor.editor'] = array(
'title' => 'Formatted text editor',
'version' => VERSION,
'js' => array(

Dries Buytaert
committed
$path . '/js/editor.formattedTextEditor.js' => array(
'scope' => 'footer',
'attributes' => array('defer' => TRUE),
),
array(
'type' => 'setting',
'data' => array(
'editor' => array(
'getUntransformedTextURL' => url('editor/!entity_type/!id/!field_name/!langcode/!view_mode'),
)
)
),
),
'dependencies' => array(
array('edit', 'edit'),
array('editor', 'drupal.editor'),
array('system', 'drupal.ajax'),
array('system', 'drupalSettings'),
),
);

Angie Byron
committed
return $libraries;
}
/**
* Implements hook_menu().
*/
function editor_menu() {
// @todo Remove this menu item in http://drupal.org/node/1954892 when theme
// callbacks are replaced with something else.
$items['editor/%/%/%/%/%'] = array(
'route_name' => 'editor_field_untransformed_text',
'theme callback' => 'ajax_base_page_theme',
);
return $items;
}

Angie Byron
committed
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
/**
* Implements hook_form_FORM_ID_alter().
*/
function editor_form_filter_admin_overview_alter(&$form, $form_state) {
// @todo Cleanup column injection: http://drupal.org/node/1876718
// Splice in the column for "Text editor" into the header.
$position = array_search('name', $form['formats']['#header']) + 1;
$start = array_splice($form['formats']['#header'], 0, $position, array('editor' => t('Text editor')));
$form['formats']['#header'] = array_merge($start, $form['formats']['#header']);
// Then splice in the name of each text editor for each text format.
$editors = drupal_container()->get('plugin.manager.editor')->getDefinitions();
foreach (element_children($form['formats']) as $format_id) {
$editor = editor_load($format_id);
$editor_name = ($editor && isset($editors[$editor->editor])) ? $editors[$editor->editor]['label'] : drupal_placeholder('—');
$editor_column['editor'] = array('#markup' => $editor_name);
$position = array_search('name', array_keys($form['formats'][$format_id])) + 1;
$start = array_splice($form['formats'][$format_id], 0, $position, $editor_column);
$form['formats'][$format_id] = array_merge($start, $form['formats'][$format_id]);
}
}
/**
* Implements hook_form_FORM_ID_alter().
*/
function editor_form_filter_admin_format_form_alter(&$form, &$form_state) {
if (!isset($form_state['editor'])) {
$format_id = $form['#format']->format;
$form_state['editor'] = editor_load($format_id);
$form_state['editor_manager'] = drupal_container()->get('plugin.manager.editor');
}
$editor = $form_state['editor'];
$manager = $form_state['editor_manager'];
// Associate a text editor with this text format.
$editor_options = $manager->listOptions();
$form['editor'] = array(

Dries Buytaert
committed
// Position the editor selection before the filter settings (weight of 0),
// but after the filter label and name (weight of -20).
'#weight' => -9,
);
$form['editor']['editor'] = array(

Angie Byron
committed
'#type' => 'select',
'#title' => t('Text editor'),
'#options' => $editor_options,
'#empty_option' => t('None'),
'#default_value' => $editor ? $editor->editor : '',
'#ajax' => array(
'trigger_as' => array('name' => 'editor_configure'),
'callback' => 'editor_form_filter_admin_form_ajax',
'wrapper' => 'editor-settings-wrapper',
),

Dries Buytaert
committed
'#weight' => -10,

Angie Byron
committed
);

Dries Buytaert
committed
$form['editor']['configure'] = array(

Angie Byron
committed
'#type' => 'submit',
'#name' => 'editor_configure',
'#value' => t('Configure'),
'#limit_validation_errors' => array(array('editor')),
'#submit' => array('editor_form_filter_admin_format_editor_configure'),
'#ajax' => array(
'callback' => 'editor_form_filter_admin_form_ajax',
'wrapper' => 'editor-settings-wrapper',
),

Dries Buytaert
committed
'#weight' => -10,

Angie Byron
committed
'#attributes' => array('class' => array('js-hide')),
);
// If there aren't any options (other than "None"), disable the select list.
if (empty($editor_options)) {

Dries Buytaert
committed
$form['editor']['editor']['#disabled'] = TRUE;
$form['editor']['editor']['#description'] = t('This option is disabled because no modules that provide a text editor are currently enabled.');

Angie Byron
committed
}

Dries Buytaert
committed
$form['editor']['settings'] = array(

Angie Byron
committed
'#tree' => TRUE,
'#weight' => -8,
'#type' => 'container',
'#id' => 'editor-settings-wrapper',
);
// Add editor-specific validation and submit handlers.
if ($editor) {
$plugin = $manager->createInstance($editor->editor);
$settings_form = array();
$settings_form['#element_validate'][] = array($plugin, 'settingsFormValidate');

Dries Buytaert
committed
$form['editor']['settings']['subform'] = $plugin->settingsForm($settings_form, $form_state, $editor);
$form['editor']['settings']['subform']['#parents'] = array('editor', 'settings');

Angie Byron
committed
$form['#submit'][] = array($plugin, 'settingsFormSubmit');
}

Alex Pott
committed
$form['#validate'][] = 'editor_form_filter_admin_format_validate';

Angie Byron
committed
$form['#submit'][] = 'editor_form_filter_admin_format_submit';
}
/**
* Button submit handler for filter_admin_format_form()'s 'editor_configure' button.
*/
function editor_form_filter_admin_format_editor_configure($form, &$form_state) {
$editor = $form_state['editor'];

Dries Buytaert
committed
if (isset($form_state['values']['editor']['editor'])) {
if ($form_state['values']['editor']['editor'] === '') {

Angie Byron
committed
$form_state['editor'] = FALSE;
}

Dries Buytaert
committed
elseif (empty($editor) || $form_state['values']['editor']['editor'] !== $editor->editor) {

Angie Byron
committed
$editor = entity_create('editor', array(
'format' => $form['#format']->format,

Dries Buytaert
committed
'editor' => $form_state['values']['editor']['editor'],

Angie Byron
committed
));
$form_state['editor'] = $editor;
}
}
$form_state['rebuild'] = TRUE;
}
/**
* AJAX callback handler for filter_admin_format_form().
*/
function editor_form_filter_admin_form_ajax($form, &$form_state) {

Dries Buytaert
committed
return $form['editor']['settings'];

Angie Byron
committed
}

Alex Pott
committed
/**
* Additional validate handler for filter_admin_format_form().
*/
function editor_form_filter_admin_format_validate($form, &$form_state) {
// This validate handler is not applicable when using the 'Configure' button.
if ($form_state['triggering_element']['#name'] === 'editor_configure') {
return;
}
// When using this form with JavaScript disabled in the browser, the the
// 'Configure' button won't be clicked automatically. So, when the user has
// selected a text editor and has then clicked 'Save configuration', we should
// point out that the user must still configure the text editor.
if ($form_state['values']['editor']['editor'] !== '' && $form_state['editor'] === FALSE) {
form_set_error('editor][editor', t('You must configure the selected text editor.'));
}
}

Angie Byron
committed
/**
* Additional submit handler for filter_admin_format_form().
*/
function editor_form_filter_admin_format_submit($form, &$form_state) {
// Delete the existing editor if disabling or switching between editors.
$format_id = $form['#format']->format;
$original_editor = editor_load($format_id);
if ($original_editor && $original_editor->editor != $form_state['values']['editor']) {
$original_editor->delete();
}
// Create a new editor or update the existing editor.

Alex Pott
committed
if ($form_state['editor'] !== FALSE) {
// Ensure the text format is set: when creating a new text format, this
// would equal the empty string.
$form_state['editor']->format = $form['#format']->format;

Dries Buytaert
committed
$form_state['editor']->settings = $form_state['values']['editor']['settings'];

Angie Byron
committed
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
$form_state['editor']->save();
}
}
/**
* Loads an individual configured text editor based on text format ID.
*
* @return \Drupal\editor\Plugin\Core\Entity\Editor|FALSE
* A text editor object, or FALSE.
*/
function editor_load($format_id) {
// Load all the editors at once here, assuming that either no editors or more
// than one editor will be needed on a page (such as having multiple text
// formats for administrators). Loading a small number of editors all at once
// is more efficient than loading multiple editors individually.
$editors = entity_load_multiple('editor');
return isset($editors[$format_id]) ? $editors[$format_id] : FALSE;
}
/**
* Additional #pre_render callback for 'text_format' elements.
*/
function editor_pre_render_format($element) {
// Allow modules to programmatically enforce no client-side editor by setting
// the #editor property to FALSE.
if (isset($element['#editor']) && !$element['#editor']) {
return $element;
}
// filter_process_format() copies properties to the expanded 'value' child
// element. Skip this text format widget, if it contains no 'format' or when
// the current user does not have access to edit the value.
if (!isset($element['format']) || !empty($element['value']['#disabled'])) {
return $element;
}
$format_ids = array_keys($element['format']['format']['#options']);
// Early-return if no text editor is associated with any of the text formats.
if (count(entity_load_multiple('editor', $format_ids)) === 0) {
return $element;
}
// Use a hidden element for a single text format.
$field_id = $element['value']['#id'];
if (!$element['format']['format']['#access']) {
// Use the first (and only) available text format.
$format_id = $format_ids[0];
$element['format']['editor'] = array(
'#type' => 'hidden',
'#name' => $element['format']['format']['#name'],
'#value' => $format_id,
'#attributes' => array(
'class' => array('editor'),
'data-editor-for' => $field_id,
),
);
}
// Otherwise, attach to text format selector.
else {
$element['format']['format']['#attributes']['class'][] = 'editor';
$element['format']['format']['#attributes']['data-editor-for'] = $field_id;
}
// Attach Text Editor module's (this module) library.
$element['#attached']['library'][] = array('editor', 'drupal.editor');
// Attach attachments for all available editors.
$manager = drupal_container()->get('plugin.manager.editor');
$element['#attached'] = NestedArray::mergeDeep($element['#attached'], $manager->getAttachments($format_ids));
return $element;
}