Completed
Push — resource-url-generator ( 57b696...53dbe7 )
by Sam
11:41 queued 02:32
created

TinyMCEConfig::getAdminPath()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nc 2
nop 0
dl 0
loc 8
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace SilverStripe\Forms\HTMLEditor;
4
5
use SilverStripe\Core\Convert;
6
use SilverStripe\Control\Controller;
7
use SilverStripe\Control\Director;
8
use SilverStripe\Core\Manifest\ModuleLoader;
9
use SilverStripe\i18n\i18n;
10
use SilverStripe\View\Requirements;
11
use SilverStripe\View\SSViewer;
12
use SilverStripe\View\ThemeResourceLoader;
13
use TinyMCE_Compressor;
14
use Exception;
15
16
/**
17
 * Default configuration for HtmlEditor specific to tinymce
18
 */
19
class TinyMCEConfig extends HTMLEditorConfig
20
{
21
    /**
22
     * @config
23
     * @var array
24
     */
25
    private static $tinymce_lang = [
26
        'ar_EG' => 'ar',
27
        'ca_AD' => 'ca',
28
        'ca_ES' => 'ca',
29
        'cs_CZ' => 'cs',
30
        'cy_GB' => 'cy',
31
        'da_DK' => 'da',
32
        'da_GL' => 'da',
33
        'de_AT' => 'de',
34
        'de_BE' => 'de',
35
        'de_CH' => 'de',
36
        'de_DE' => 'de',
37
        'de_LI' => 'de',
38
        'de_LU' => 'de',
39
        'de_BR' => 'de',
40
        'de_US' => 'de',
41
        'el_CY' => 'el',
42
        'el_GR' => 'el',
43
        'es_AR' => 'es',
44
        'es_BO' => 'es',
45
        'es_CL' => 'es',
46
        'es_CO' => 'es',
47
        'es_CR' => 'es',
48
        'es_CU' => 'es',
49
        'es_DO' => 'es',
50
        'es_EC' => 'es',
51
        'es_ES' => 'es',
52
        'es_GQ' => 'es',
53
        'es_GT' => 'es',
54
        'es_HN' => 'es',
55
        'es_MX' => 'es',
56
        'es_NI' => 'es',
57
        'es_PA' => 'es',
58
        'es_PE' => 'es',
59
        'es_PH' => 'es',
60
        'es_PR' => 'es',
61
        'es_PY' => 'es',
62
        'es_SV' => 'es',
63
        'es_UY' => 'es',
64
        'es_VE' => 'es',
65
        'es_AD' => 'es',
66
        'es_BZ' => 'es',
67
        'es_US' => 'es',
68
        'fa_AF' => 'fa',
69
        'fa_IR' => 'fa',
70
        'fa_PK' => 'fa',
71
        'fi_FI' => 'fi',
72
        'fi_SE' => 'fi',
73
        'fr_BE' => 'fr',
74
        'fr_BF' => 'fr',
75
        'fr_BI' => 'fr',
76
        'fr_BJ' => 'fr',
77
        'fr_CA' => 'fr_ca',
78
        'fr_CF' => 'fr',
79
        'fr_CG' => 'fr',
80
        'fr_CH' => 'fr',
81
        'fr_CI' => 'fr',
82
        'fr_CM' => 'fr',
83
        'fr_DJ' => 'fr',
84
        'fr_DZ' => 'fr',
85
        'fr_FR' => 'fr',
86
        'fr_GA' => 'fr',
87
        'fr_GF' => 'fr',
88
        'fr_GN' => 'fr',
89
        'fr_GP' => 'fr',
90
        'fr_HT' => 'fr',
91
        'fr_KM' => 'fr',
92
        'fr_LU' => 'fr',
93
        'fr_MA' => 'fr',
94
        'fr_MC' => 'fr',
95
        'fr_MG' => 'fr',
96
        'fr_ML' => 'fr',
97
        'fr_MQ' => 'fr',
98
        'fr_MU' => 'fr',
99
        'fr_NC' => 'fr',
100
        'fr_NE' => 'fr',
101
        'fr_PF' => 'fr',
102
        'fr_PM' => 'fr',
103
        'fr_RE' => 'fr',
104
        'fr_RW' => 'fr',
105
        'fr_SC' => 'fr',
106
        'fr_SN' => 'fr',
107
        'fr_SY' => 'fr',
108
        'fr_TD' => 'fr',
109
        'fr_TG' => 'fr',
110
        'fr_TN' => 'fr',
111
        'fr_VU' => 'fr',
112
        'fr_WF' => 'fr',
113
        'fr_YT' => 'fr',
114
        'fr_GB' => 'fr',
115
        'fr_US' => 'fr',
116
        'he_IL' => 'he',
117
        'hu_HU' => 'hu',
118
        'hu_AT' => 'hu',
119
        'hu_RO' => 'hu',
120
        'hu_RS' => 'hu',
121
        'is_IS' => 'is',
122
        'it_CH' => 'it',
123
        'it_IT' => 'it',
124
        'it_SM' => 'it',
125
        'it_FR' => 'it',
126
        'it_HR' => 'it',
127
        'it_US' => 'it',
128
        'it_VA' => 'it',
129
        'ja_JP' => 'ja',
130
        'ko_KP' => 'ko',
131
        'ko_KR' => 'ko',
132
        'ko_CN' => 'ko',
133
        'mi_NZ' => 'mi_NZ',
134
        'nb_NO' => 'nb',
135
        'nb_SJ' => 'nb',
136
        'nl_AN' => 'nl',
137
        'nl_AW' => 'nl',
138
        'nl_BE' => 'nl',
139
        'nl_NL' => 'nl',
140
        'nl_SR' => 'nl',
141
        'nn_NO' => 'nn',
142
        'pl_PL' => 'pl',
143
        'pl_UA' => 'pl',
144
        'pt_AO' => 'pt',
145
        'pt_BR' => 'pt',
146
        'pt_CV' => 'pt',
147
        'pt_GW' => 'pt',
148
        'pt_MZ' => 'pt',
149
        'pt_PT' => 'pt',
150
        'pt_ST' => 'pt',
151
        'pt_TL' => 'pt',
152
        'ro_MD' => 'ro',
153
        'ro_RO' => 'ro',
154
        'ro_RS' => 'ro',
155
        'ru_BY' => 'ru',
156
        'ru_KG' => 'ru',
157
        'ru_KZ' => 'ru',
158
        'ru_RU' => 'ru',
159
        'ru_SJ' => 'ru',
160
        'ru_UA' => 'ru',
161
        'si_LK' => 'si',
162
        'sk_SK' => 'sk',
163
        'sk_RS' => 'sk',
164
        'sq_AL' => 'sq',
165
        'sr_BA' => 'sr',
166
        'sr_ME' => 'sr',
167
        'sr_RS' => 'sr',
168
        'sv_FI' => 'sv',
169
        'sv_SE' => 'sv',
170
        'tr_CY' => 'tr',
171
        'tr_TR' => 'tr',
172
        'tr_DE' => 'tr',
173
        'tr_MK' => 'tr',
174
        'uk_UA' => 'uk',
175
        'vi_VN' => 'vi',
176
        'vi_US' => 'vi',
177
        'zh_CN' => 'zh-cn',
178
        'zh_HK' => 'zh-cn',
179
        'zh_MO' => 'zh-cn',
180
        'zh_SG' => 'zh-cn',
181
        'zh_TW' => 'zh-tw',
182
        'zh_ID' => 'zh-cn',
183
        'zh_MY' => 'zh-cn',
184
        'zh_TH' => 'zh-cn',
185
        'zh_US' => 'zn-cn',
186
    ];
187
188
    /**
189
     * Location of module relative to BASE_DIR. This must contain the following dirs
190
     * - plugins
191
     * - themes
192
     * - skins
193
     *
194
     * If left blank defaults to [admin dir]/tinyme
195
     *
196
     * @config
197
     * @var string
198
     */
199
    private static $base_dir = null;
200
201
    /**
202
     * TinyMCE JS settings
203
     *
204
     * @link https://www.tinymce.com/docs/configure/
205
     *
206
     * @var array
207
     */
208
    protected $settings = array(
209
        'fix_list_elements' => true, // https://www.tinymce.com/docs/configure/content-filtering/#fix_list_elements
210
        'friendly_name' => '(Please set a friendly name for this config)',
211
        'priority' => 0, // used for Per-member config override
212
        'browser_spellcheck' => true,
213
        'body_class' => 'typography',
214
        'elementpath' => false, // https://www.tinymce.com/docs/configure/editor-appearance/#elementpath
215
        'relative_urls' => true,
216
        'remove_script_host' => true,
217
        'convert_urls' => false, // Prevent site-root images being rewritten to base relative
218
        'menubar' => false,
219
        'language' => 'en',
220
    );
221
222
    /**
223
     * Holder list of enabled plugins
224
     *
225
     * @var array
226
     */
227
    protected $plugins = array(
228
        'table' => null,
229
        'emoticons' => null,
230
        'paste' => null,
231
        'code' => null,
232
        'link' => null,
233
        'importcss' => null,
234
    );
235
236
    /**
237
     * Theme name
238
     *
239
     * @var string
240
     */
241
    protected $theme = 'modern';
242
243
    /**
244
     * Get the theme
245
     *
246
     * @return string
247
     */
248
    public function getTheme()
249
    {
250
        return $this->theme;
251
    }
252
253
    /**
254
     * Set the theme name
255
     *
256
     * @param string $theme
257
     * @return $this
258
     */
259
    public function setTheme($theme)
260
    {
261
        $this->theme = $theme;
262
        return $this;
263
    }
264
265
    /**
266
     * Holder list of buttons, organised by line. This array is 1-based indexed array
267
     *
268
     * {@link https://www.tinymce.com/docs/advanced/editor-control-identifiers/#toolbarcontrols}
269
     *
270
     * @var array
271
     */
272
    protected $buttons = array(
273
        1 => array(
274
            'bold', 'italic', 'underline', 'removeformat', '|',
275
            'alignleft', 'aligncenter', 'alignright', 'alignjustify', '|',
276
            'bullist', 'numlist', 'outdent', 'indent',
277
        ),
278
        2 => array(
279
            'formatselect', '|',
280
            'paste', 'pastetext', '|',
281
            'table', 'sslink', 'unlink', '|',
282
            'code'
283
        ),
284
        3 => array()
285
    );
286
287
    public function getOption($key)
288
    {
289
        if (isset($this->settings[$key])) {
290
            return $this->settings[$key];
291
        }
292
        return null;
293
    }
294
295
    public function setOption($key, $value)
296
    {
297
        $this->settings[$key] = $value;
298
        return $this;
299
    }
300
301
    public function setOptions($options)
302
    {
303
        foreach ($options as $key => $value) {
304
            $this->settings[$key] = $value;
305
        }
306
        return $this;
307
    }
308
309
    /**
310
     * Get all settings
311
     *
312
     * @return array
313
     */
314
    protected function getSettings()
315
    {
316
        return $this->settings;
317
    }
318
319
    public function getAttributes()
320
    {
321
        return [
322
            'data-editor' => 'tinyMCE', // Register ss.editorWrappers.tinyMCE
323
            'data-config' => Convert::array2json($this->getConfig())
324
        ];
325
    }
326
327
    /**
328
     * Enable one or several plugins. Will maintain unique list if already
329
     * enabled plugin is re-passed. If passed in as a map of plugin-name to path,
330
     * the plugin will be loaded by tinymce.PluginManager.load() instead of through tinyMCE.init().
331
     * Keep in mind that these externals plugins require a dash-prefix in their name.
332
     *
333
     * @see http://wiki.moxiecode.com/index.php/TinyMCE:API/tinymce.PluginManager/load
334
     *
335
     * If passing in a non-associative array, the plugin name should be located in the standard tinymce
336
     * plugins folder.
337
     *
338
     * If passing in an associative array, the key of each item should be the plugin name.
339
     * The value of each item is one of:
340
     *  - null - Will be treated as a stardard plugin in the standard location
341
     *  - relative path - Will be treated as a relative url
342
     *  - absolute url - Some url to an external plugin
343
     *
344
     * @param string|array $plugin,... a string, or several strings, or a single array of strings - The plugins to enable
0 ignored issues
show
Documentation introduced by
There is no parameter named $plugin,.... Did you maybe mean $plugin?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
345
     * @return $this
346
     */
347
    public function enablePlugins($plugin)
0 ignored issues
show
Unused Code introduced by
The parameter $plugin is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
348
    {
349
        $plugins = func_get_args();
350
        if (is_array(current($plugins))) {
351
            $plugins = current($plugins);
352
        }
353
        foreach ($plugins as $name => $path) {
354
            // if plugins are passed without a path
355
            if (is_numeric($name)) {
356
                $name = $path;
357
                $path = null;
358
            }
359
            if (!array_key_exists($name, $this->plugins)) {
360
                $this->plugins[$name] = $path;
361
            }
362
        }
363
        return $this;
364
    }
365
366
    /**
367
     * Enable one or several plugins. Will properly handle being passed a plugin that is already disabled
368
     * @param string|array $plugin,... a string, or several strings, or a single array of strings - The plugins to enable
0 ignored issues
show
Documentation introduced by
There is no parameter named $plugin,.... Did you maybe mean $plugin?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
369
     * @return $this
370
     */
371
    public function disablePlugins($plugin)
0 ignored issues
show
Unused Code introduced by
The parameter $plugin is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
372
    {
373
        $plugins = func_get_args();
374
        if (is_array(current($plugins))) {
375
            $plugins = current($plugins);
376
        }
377
        foreach ($plugins as $name) {
378
            unset($this->plugins[$name]);
379
        }
380
        return $this;
381
    }
382
383
    /**
384
     * Gets the list of all enabled plugins as an associative array.
385
     * Array keys are the plugin names, and values are potentially the plugin location
386
     *
387
     * @return array
388
     */
389
    public function getPlugins()
390
    {
391
        return $this->plugins;
392
    }
393
394
    /**
395
     * Get list of plugins without custom locations, which is the set of
396
     * plugins which can be loaded via the standard plugin path, and could
397
     * potentially be minified
398
     *
399
     * @return array
400
     */
401
    public function getInternalPlugins()
402
    {
403
        // Return only plugins with no custom url
404
        $plugins = [];
405
        foreach ($this->getPlugins() as $name => $url) {
406
            if (empty($url)) {
407
                $plugins[] = $name;
408
            }
409
        }
410
        return $plugins;
411
    }
412
413
    /**
414
     * Get all button rows, skipping empty rows
415
     *
416
     * @return array
417
     */
418
    public function getButtons()
419
    {
420
        return array_filter($this->buttons);
421
    }
422
423
    /**
424
     * Totally re-set the buttons on a given line
425
     *
426
     * @param int $line The line number to redefine, from 1 to 3
427
     * @param string $buttons,... A string or several strings, or a single array of strings.
0 ignored issues
show
Documentation introduced by
There is no parameter named $buttons,.... Did you maybe mean $buttons?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
428
     * The button names to assign to this line.
429
     * @return $this
430
     */
431
    public function setButtonsForLine($line, $buttons)
432
    {
433
        if (func_num_args() > 2) {
434
            $buttons = func_get_args();
435
            array_shift($buttons);
436
        }
437
        $this->buttons[$line] = is_array($buttons) ? $buttons : array($buttons);
438
        return $this;
439
    }
440
441
    /**
442
     * Add buttons to the end of a line
443
     * @param int $line The line number to redefine, from 1 to 3
444
     * @param string $buttons,... A string or several strings, or a single array of strings.
0 ignored issues
show
Documentation introduced by
There is no parameter named $buttons,.... Did you maybe mean $buttons?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
445
     * The button names to add to this line
446
     * @return $this
447
     */
448
    public function addButtonsToLine($line, $buttons)
449
    {
450
        if (func_num_args() > 2) {
451
            $buttons = func_get_args();
452
            array_shift($buttons);
453
        }
454
        if (!is_array($buttons)) {
455
            $buttons = [$buttons];
456
        }
457
        foreach ($buttons as $button) {
458
            $this->buttons[$line][] = $button;
459
        }
460
        return $this;
461
    }
462
463
    /**
464
     * Internal function for adding and removing buttons related to another button
465
     * @param string $name The name of the button to modify
466
     * @param int $offset The offset relative to that button to perform an array_splice at.
467
     * 0 for before $name, 1 for after.
468
     * @param int $del The number of buttons to remove at the position given by index(string) + offset
469
     * @param mixed $add An array or single item to insert at the position given by index(string) + offset,
470
     * or null for no insertion
471
     * @return bool True if $name matched a button, false otherwise
472
     */
473
    protected function modifyButtons($name, $offset, $del = 0, $add = null)
474
    {
475
        foreach ($this->buttons as &$buttons) {
476
            if (($idx = array_search($name, $buttons)) !== false) {
477
                if ($add) {
478
                    array_splice($buttons, $idx + $offset, $del, $add);
479
                } else {
480
                    array_splice($buttons, $idx + $offset, $del);
481
                }
482
                return true;
483
            }
484
        }
485
        return false;
486
    }
487
488
    /**
489
     * Insert buttons before the first occurance of another button
490
     * @param string $before the name of the button to insert other buttons before
491
     * @param string $buttons,... a string, or several strings, or a single array of strings.
0 ignored issues
show
Documentation introduced by
There is no parameter named $buttons,.... Did you maybe mean $buttons?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
492
     * The button names to insert before that button
493
     * @return bool True if insertion occured, false if it did not (because the given button name was not found)
494
     */
495 View Code Duplication
    public function insertButtonsBefore($before, $buttons)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
496
    {
497
        if (func_num_args() > 2) {
498
            $buttons = func_get_args();
499
            array_shift($buttons);
500
        }
501
        if (!is_array($buttons)) {
502
            $buttons = [$buttons];
503
        }
504
        return $this->modifyButtons($before, 0, 0, $buttons);
505
    }
506
507
    /**
508
     * Insert buttons after the first occurance of another button
509
     * @param string $after the name of the button to insert other buttons before
510
     * @param string $buttons,... a string, or several strings, or a single array of strings.
0 ignored issues
show
Documentation introduced by
There is no parameter named $buttons,.... Did you maybe mean $buttons?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
511
     * The button names to insert after that button
512
     * @return bool True if insertion occured, false if it did not (because the given button name was not found)
513
     */
514 View Code Duplication
    public function insertButtonsAfter($after, $buttons)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
515
    {
516
        if (func_num_args() > 2) {
517
            $buttons = func_get_args();
518
            array_shift($buttons);
519
        }
520
        if (!is_array($buttons)) {
521
            $buttons = [$buttons];
522
        }
523
        return $this->modifyButtons($after, 1, 0, $buttons);
524
    }
525
526
    /**
527
     * Remove the first occurance of buttons
528
     * @param string $buttons,... one or more strings - the name of the buttons to remove
0 ignored issues
show
Documentation introduced by
There is no parameter named $buttons,.... Did you maybe mean $buttons?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function. It has, however, found a similar but not annotated parameter which might be a good fit.

Consider the following example. The parameter $ireland is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $ireland
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was changed, but the annotation was not.

Loading history...
529
     */
530 View Code Duplication
    public function removeButtons($buttons)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
531
    {
532
        if (func_num_args() > 1) {
533
            $buttons = func_get_args();
534
        }
535
        if (!is_array($buttons)) {
536
            $buttons = [$buttons];
537
        }
538
        foreach ($buttons as $button) {
539
            $this->modifyButtons($button, 0, 1);
540
        }
541
    }
542
543
    /**
544
     * Generate the JavaScript that will set TinyMCE's configuration:
545
     * - Parse all configurations into JSON objects to be used in JavaScript
546
     * - Includes TinyMCE and configurations using the {@link Requirements} system
547
     *
548
     * @return array
549
     */
550
    protected function getConfig()
551
    {
552
        $settings = $this->getSettings();
553
554
        // https://www.tinymce.com/docs/configure/url-handling/#document_base_url
555
        $settings['document_base_url'] = Director::absoluteBaseURL();
556
557
        // https://www.tinymce.com/docs/api/class/tinymce.editormanager/#baseURL
558
        $tinyMCEBaseURL = $this->getAdminModule()->getResourceURL('thirdparty/tinymce');
559
        $settings['baseURL'] = $tinyMCEBaseURL;
560
561
        // map all plugins to absolute urls for loading
562
        $plugins = array();
563
        foreach ($this->getPlugins() as $plugin => $path) {
564
            if (!$path) {
565
                // Empty paths: Convert to urls in standard base url
566
                $path = Controller::join_links(
567
                    $tinyMCEBaseURL,
568
                    "plugins/{$plugin}/plugin.min.js"
569
                );
570
            } elseif (!Director::is_absolute_url($path)) {
571
                // Non-absolute urls are made absolute
572
                $path = Director::absoluteURL($path);
573
            }
574
            $plugins[$plugin] = $path;
575
        }
576
577
        // https://www.tinymce.com/docs/configure/integration-and-setup/#external_plugins
578
        if ($plugins) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $plugins of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using ! empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
579
            $settings['external_plugins'] = $plugins;
580
        }
581
582
        // https://www.tinymce.com/docs/configure/editor-appearance/#groupingtoolbarcontrols
583
        $buttons = $this->getButtons();
584
        $settings['toolbar'] = [];
585
        foreach ($buttons as $rowButtons) {
586
            $row = implode(' ', $rowButtons);
587
            if (count($buttons) > 1) {
588
                $settings['toolbar'][] = $row;
589
            } else {
590
                $settings['toolbar'] = $row;
591
            }
592
        }
593
594
        // https://www.tinymce.com/docs/configure/content-appearance/#content_css
595
        $settings['content_css'] = $this->getEditorCSS();
596
597
        // https://www.tinymce.com/docs/configure/editor-appearance/#theme_url
598
        $theme = $this->getTheme();
599
        if (!Director::is_absolute_url($theme)) {
600
            $theme = Controller::join_links($tinyMCEBaseURL, "themes/{$theme}/theme.min.js");
601
        }
602
        $settings['theme_url'] = $theme;
603
604
        // Send back
605
        return $settings;
606
    }
607
608
    /**
609
     * Get location of all editor.css files
610
     *
611
     * @return array
612
     */
613
    protected function getEditorCSS()
614
    {
615
        $editor = array();
616
617
        // Add standard editor.css
618
        $editor[] = $this->getAdminModule()->getResourceURL('client/dist/styles/editor.css');
619
620
        // Themed editor.css
621
        $themedEditor = ThemeResourceLoader::inst()->findThemedCSS('editor', SSViewer::get_themes());
622
        if ($themedEditor) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $themedEditor of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
623
            $editor[] = Director::absoluteURL($themedEditor, Director::BASE);
624
        }
625
626
        return $editor;
627
    }
628
629
    /**
630
     * Generate gzipped TinyMCE configuration including plugins and languages.
631
     * This ends up "pre-loading" TinyMCE bundled with the required plugins
632
     * so that multiple HTTP requests on the client don't need to be made.
633
     *
634
     * @return string
635
     */
636
    public function getScriptURL()
637
    {
638
        // If gzip is disabled just return core script url
639
        $useGzip = HTMLEditorField::config()->get('use_gzip');
640
        if (!$useGzip) {
641
            return $this->getTinyMCEPath() . '/tinymce.min.js';
642
        }
643
644
        // tinyMCE JS requirement
645
        $gzipPath = BASE_PATH . '/' . $this->getTinyMCEPath() . '/tiny_mce_gzip.php';
646
        if (!file_exists($gzipPath)) {
647
            throw new Exception("HTMLEditorField.use_gzip enabled, but file $gzipPath does not exist!");
648
        }
649
650
        require_once $gzipPath;
651
652
        $tag = TinyMCE_Compressor::renderTag(array(
653
            'url' => $this->getTinyMCEPath() . '/tiny_mce_gzip.php',
654
            'plugins' => implode(',', $this->getInternalPlugins()),
655
            'themes' => $this->getTheme(),
656
            'languages' => $this->getOption('language')
657
        ), true);
658
        preg_match('/src="([^"]*)"/', $tag, $matches);
659
660
        return html_entity_decode($matches[1]);
661
    }
662
663
    public function init()
664
    {
665
        // include TinyMCE Javascript
666
        Requirements::javascript($this->getScriptURL());
667
    }
668
669
670
    /**
671
     * Get the current tinyMCE language
672
     *
673
     * @return string Language
674
     */
675
    public static function get_tinymce_lang()
676
    {
677
        $lang = static::config()->get('tinymce_lang');
678
        $locale = i18n::get_locale();
679
        if (isset($lang[$locale])) {
680
            return $lang[$locale];
681
        }
682
        return 'en';
683
    }
684
685
    /**
686
     * @return string|false
687
     */
688
    public function getTinyMCEPath()
689
    {
690
        $configDir = static::config()->get('base_dir');
691
        if ($configDir) {
692
            return $configDir;
693
        }
694
695
        if ($admin = $this->getAdminModule()) {
696
            return $admin->getRelativeResourcePath('thirdparty/tinymce');
697
        }
698
699
        throw new Exception(sprintf(
700
            'If the silverstripe/admin module is not installed,
701
            you must set the TinyMCE path in %s.base_dir',
702
            __CLASS__
703
        ));
704
    }
705
706
    /**
707
     * @return \SilverStripe\Core\Manifest\Module
708
     */
709
    protected function getAdminModule()
710
    {
711
        return ModuleLoader::getModule('silverstripe/admin');
712
    }
713
}
714