7b3386efe034de7d248ce3866483873a20e92b52
[yaffs-website] / web / core / modules / ckeditor / src / Plugin / CKEditorPlugin / StylesCombo.php
1 <?php
2
3 namespace Drupal\ckeditor\Plugin\CKEditorPlugin;
4
5 use Drupal\ckeditor\CKEditorPluginBase;
6 use Drupal\ckeditor\CKEditorPluginConfigurableInterface;
7 use Drupal\Core\Form\FormStateInterface;
8 use Drupal\editor\Entity\Editor;
9
10 /**
11  * Defines the "stylescombo" plugin.
12  *
13  * @CKEditorPlugin(
14  *   id = "stylescombo",
15  *   label = @Translation("Styles dropdown")
16  * )
17  */
18 class StylesCombo extends CKEditorPluginBase implements CKEditorPluginConfigurableInterface {
19
20   /**
21    * {@inheritdoc}
22    */
23   public function isInternal() {
24     return TRUE;
25   }
26
27   /**
28    * {@inheritdoc}
29    */
30   public function getFile() {
31     // This plugin is already part of Drupal core's CKEditor build.
32     return FALSE;
33   }
34
35   /**
36    * {@inheritdoc}
37    */
38   public function getConfig(Editor $editor) {
39     $config = [];
40     $settings = $editor->getSettings();
41     if (!isset($settings['plugins']['stylescombo']['styles'])) {
42       return $config;
43     }
44     $styles = $settings['plugins']['stylescombo']['styles'];
45     $config['stylesSet'] = $this->generateStylesSetSetting($styles);
46     return $config;
47   }
48
49   /**
50    * {@inheritdoc}
51    */
52   public function getButtons() {
53     return [
54       'Styles' => [
55         'label' => $this->t('Font style'),
56         'image_alternative' => [
57           '#type' => 'inline_template',
58           '#template' => '<a href="#" role="button" aria-label="{{ styles_text }}"><span class="ckeditor-button-dropdown">{{ styles_text }}<span class="ckeditor-button-arrow"></span></span></a>',
59           '#context' => [
60             'styles_text' => $this->t('Styles'),
61           ],
62         ],
63       ],
64     ];
65   }
66
67   /**
68    * {@inheritdoc}
69    */
70   public function settingsForm(array $form, FormStateInterface $form_state, Editor $editor) {
71     // Defaults.
72     $config = ['styles' => ''];
73     $settings = $editor->getSettings();
74     if (isset($settings['plugins']['stylescombo'])) {
75       $config = $settings['plugins']['stylescombo'];
76     }
77
78     $form['styles'] = [
79       '#title' => $this->t('Styles'),
80       '#title_display' => 'invisible',
81       '#type' => 'textarea',
82       '#default_value' => $config['styles'],
83       '#description' => $this->t('A list of classes that will be provided in the "Styles" dropdown. Enter one or more classes on each line in the format: element.classA.classB|Label. Example: h1.title|Title. Advanced example: h1.fancy.title|Fancy title.<br />These styles should be available in your theme\'s CSS file.'),
84       '#attached' => [
85         'library' => ['ckeditor/drupal.ckeditor.stylescombo.admin'],
86       ],
87       '#element_validate' => [
88         [$this, 'validateStylesValue'],
89       ],
90     ];
91
92     return $form;
93   }
94
95   /**
96    * #element_validate handler for the "styles" element in settingsForm().
97    */
98   public function validateStylesValue(array $element, FormStateInterface $form_state) {
99     $styles_setting = $this->generateStylesSetSetting($element['#value']);
100     if ($styles_setting === FALSE) {
101       $form_state->setError($element, $this->t('The provided list of styles is syntactically incorrect.'));
102     }
103     else {
104       $style_names = array_map(function ($style) { return $style['name']; }, $styles_setting);
105       if (count($style_names) !== count(array_unique($style_names))) {
106         $form_state->setError($element, $this->t('Each style must have a unique label.'));
107       }
108     }
109   }
110
111   /**
112    * Builds the "stylesSet" configuration part of the CKEditor JS settings.
113    *
114    * @see getConfig()
115    *
116    * @param string $styles
117    *   The "styles" setting.
118    * @return array|false
119    *   An array containing the "stylesSet" configuration, or FALSE when the
120    *   syntax is invalid.
121    */
122   protected function generateStylesSetSetting($styles) {
123     $styles_set = [];
124
125     // Early-return when empty.
126     $styles = trim($styles);
127     if (empty($styles)) {
128       return $styles_set;
129     }
130
131     $styles = str_replace(["\r\n", "\r"], "\n", $styles);
132     foreach (explode("\n", $styles) as $style) {
133       $style = trim($style);
134
135       // Ignore empty lines in between non-empty lines.
136       if (empty($style)) {
137         continue;
138       }
139
140       // Validate syntax: element[.class...]|label pattern expected.
141       if (!preg_match('@^ *[a-zA-Z0-9]+ *(\\.[a-zA-Z0-9_-]+ *)*\\| *.+ *$@', $style)) {
142         return FALSE;
143       }
144
145       // Parse.
146       list($selector, $label) = explode('|', $style);
147       $classes = explode('.', $selector);
148       $element = array_shift($classes);
149
150       // Build the data structure CKEditor's stylescombo plugin expects.
151       // @see http://docs.cksource.com/CKEditor_3.x/Developers_Guide/Styles
152       $configured_style = [
153         'name' => trim($label),
154         'element' => trim($element),
155       ];
156       if (!empty($classes)) {
157         $configured_style['attributes'] = [
158           'class' => implode(' ', array_map('trim', $classes))
159         ];
160       }
161       $styles_set[] = $configured_style;
162     }
163     return $styles_set;
164   }
165
166 }