Differences Between: [Versions 401 and 402]
1 <?php 2 // This file is part of Moodle - http://moodle.org/ 3 // 4 // Moodle is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // Moodle is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU General Public License for more details. 13 // 14 // You should have received a copy of the GNU General Public License 15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 16 17 namespace editor_tiny; 18 19 use context; 20 21 /** 22 * Tiny Editor Plugin manager. 23 * 24 * @package editor_tiny 25 * @copyright 2021 Andrew Lyons <andrew@nicols.co.uk> 26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 */ 28 class manager { 29 30 /** 31 * Get the configuration for all plugins. 32 * 33 * @param context $context The context that the editor is used within 34 * @param array $options The options passed in when requesting the editor 35 * @param array $fpoptions The filepicker options passed in when requesting the editor 36 * @param editor $editor The editor instance in which the plugin is initialised 37 */ 38 public function get_plugin_configuration( 39 context $context, 40 array $options = [], 41 array $fpoptions = [], 42 ?editor $editor = null 43 ): array { 44 // Get the list of plugins. 45 // Note: Disabled plugins are already removed from this list. 46 $plugins = $this->get_shipped_plugins(); 47 48 // Fetch configuration for Moodle plugins. 49 $moodleplugins = \core_component::get_plugin_list_with_class('tiny', 'plugininfo'); 50 $enabledplugins = \editor_tiny\plugininfo\tiny::get_enabled_plugins(); 51 foreach ($moodleplugins as $plugin => $classname) { 52 [, $pluginname] = explode('_', $plugin, 2); 53 if (!in_array($pluginname, $enabledplugins)) { 54 // This plugin has been disabled. 55 continue; 56 } 57 58 if (!is_a($classname, plugin::class, true)) { 59 // Skip plugins that do not implement the plugin interface. 60 debugging("Plugin {$plugin} does not implement the plugin interface", DEBUG_DEVELOPER); 61 continue; 62 } 63 64 if (!$classname::is_enabled($context, $options, $fpoptions, $editor)) { 65 // This plugin has disabled itself for some reason. 66 // This is typical for media plugins where there is no file storage. 67 continue; 68 } 69 70 // Get the plugin information, which includes the list of buttons, menu items, and configuration. 71 $plugininfo = $classname::get_plugin_info( 72 $context, 73 $options, 74 $fpoptions, 75 $editor 76 ); 77 78 // We suffix the plugin name for Moodle plugins with /plugin to avoid conflicts with Tiny plugins. 79 $plugins["{$plugin}/plugin"] = $plugininfo; 80 } 81 82 return $plugins; 83 } 84 85 /** 86 * Get a list of the buttons provided by this plugin. 87 * 88 * @return string[] 89 */ 90 protected function get_tinymce_buttons(): array { 91 // The following list is defined at: 92 // https://www.tiny.cloud/docs/advanced/available-toolbar-buttons/#thecoretoolbarbuttons. 93 return [ 94 // These are always available, without requiring additional plugins. 95 'aligncenter', 96 'alignjustify', 97 'alignleft', 98 'alignnone', 99 'alignright', 100 'blockquote', 101 'backcolor', 102 'bold', 103 'copy', 104 'cut', 105 'fontselect', 106 'fontsizeselect', 107 'forecolor', 108 'formatselect', 109 'h1', 110 'h2', 111 'h3', 112 'h4', 113 'h5', 114 'h6', 115 'indent', 116 'italic', 117 'language', 118 'lineheight', 119 'newdocument', 120 'outdent', 121 'paste', 122 'redo', 123 'remove', 124 'removeformat', 125 'selectall', 126 'strikethrough', 127 'styleselect', 128 'subscript', 129 'superscript', 130 'underline', 131 'undo', 132 'visualaid', 133 ]; 134 } 135 136 /** 137 * Get a list of the menu items provided by this plugin. 138 * 139 * @return string[] 140 */ 141 protected function get_tinymce_menuitems(): array { 142 // The following list is defined at: 143 // https://www.tiny.cloud/docs/advanced/available-menu-items/#thecoremenuitems. 144 return [ 145 'align' => 'format', 146 'backcolor' => 'format', 147 'blockformats' => 'format', 148 'bold' => 'format', 149 'codeformat' => 'format', 150 'copy' => 'copy', 151 'cut' => 'copy', 152 'forecolor' => 'format', 153 'formats' => 'format', 154 'fontformats' => 'format', 155 'fontsizes' => 'format', 156 'italic' => 'format', 157 'language' => 'format', 158 'lineheight' => 'format', 159 'newdocument' => 'file', 160 'paste' => 'copy', 161 'redo' => 'copy', 162 'removeformat' => 'format', 163 'selectall' => 'edit', 164 'strikethrough' => 'format', 165 'subscript' => 'format', 166 'superscript' => 'format', 167 'underline' => 'format', 168 'undo' => 'copy', 169 'visualaid' => 'view', 170 ]; 171 } 172 173 /** 174 * Return a list of all available plugins, including both TinyMCE shipped, and Moodle add-onis. 175 * 176 * Each plugin is returned as an array element containing: 177 * - a list of buttons (if applicable); and 178 * - a list of menuitems (if applicable). 179 * 180 * Note: Not all plugins include buttons, and not all plugins include menuitems. 181 * These array keys are optional. 182 * 183 * @return array 184 */ 185 protected function get_available_plugins(): array { 186 $plugins = $this->get_shipped_plugins(); 187 $plugins += $this->get_moodle_plugins(); 188 189 $disabledplugins = $this->get_disabled_tinymce_plugins(); 190 $plugins = array_filter($plugins, function ($plugin) use ($disabledplugins) { 191 return !in_array($plugin, $disabledplugins); 192 }, ARRAY_FILTER_USE_KEY); 193 194 return $plugins; 195 } 196 197 /** 198 * Return a list of all available plugins built into TinyMCE and not shipped as separate Moodle plugins. 199 * 200 * Each plugin is returned as an array element containing: 201 * - a list of buttons (if applicable); and 202 * - a list of menuitems (if applicable). 203 * 204 * Note: Not all plugins include buttons, and not all plugins include menuitems. 205 * These array keys are optional. 206 * 207 * @return array 208 */ 209 protected function get_shipped_plugins(): array { 210 $plugins = $this->get_tinymce_plugins(); 211 if ($this->premium_plugins_enabled()) { 212 $plugins += $this->get_premium_plugins(); 213 } 214 215 $disabledplugins = $this->get_disabled_tinymce_plugins(); 216 return array_filter($plugins, function ($plugin) use ($disabledplugins) { 217 return !in_array($plugin, $disabledplugins); 218 }, ARRAY_FILTER_USE_KEY); 219 } 220 221 /** 222 * Get a list of the core plugins with their button, and menuitem, configuration. 223 * 224 * @return array[] 225 */ 226 protected function get_tinymce_plugins(): array { 227 // The following list is defined at: 228 // https://www.tiny.cloud/docs/advanced/available-toolbar-buttons/#thecoretoolbarbuttons. 229 return [ 230 'anchor' => [ 231 'buttons' => [ 232 'anchor', 233 ], 234 'menuitems' => [ 235 'anchor' => 'insert', 236 ], 237 ], 238 'autosave' => [ 239 'buttons' => [ 240 'restoredraft', 241 ], 242 'menuitems' => [ 243 'restoredraft' => 'file', 244 ], 245 ], 246 'charmap' => [ 247 'buttons' => [ 248 'charmap', 249 ], 250 'menuitems' => [ 251 'charmap' => 'insert', 252 ], 253 ], 254 'code' => [ 255 'buttons' => [ 256 'code', 257 ], 258 'menuitems' => [ 259 'code' => 'view', 260 ], 261 ], 262 'codesample' => [ 263 'buttons' => [ 264 'codesample', 265 ], 266 'menutiems' => [ 267 'codesample' => 'insert', 268 ], 269 ], 270 'directionality' => [ 271 'buttons' => [ 272 'ltr', 273 'rtl', 274 ], 275 ], 276 'emoticons' => [ 277 'buttons' => [ 278 'emoticons', 279 ], 280 'menuitems' => [ 281 'emoticons' => 'insert', 282 ], 283 ], 284 'fullscreen' => [ 285 'buttons' => [ 286 'fullscreen', 287 ], 288 'menuitems' => [ 289 'fullscreen' => 'view', 290 ], 291 ], 292 'help' => [ 293 'buttons' => [ 294 'help', 295 ], 296 'menuitems' => [ 297 'help' => 'help', 298 ], 299 ], 300 'image' => [ 301 'buttons' => [ 302 'image', 303 ], 304 'menuitems' => [ 305 'image' => 'insert', 306 ], 307 ], 308 'insertdatetime' => [ 309 'buttons' => [ 310 'insertdatetime', 311 ], 312 'menuitems' => [ 313 'insertdatetime' => 'insert', 314 ], 315 ], 316 'link' => [ 317 'buttons' => [ 318 'link', 319 'openlink', 320 'unlink', 321 ], 322 'menuitems' => [ 323 'link' => 'insert', 324 ], 325 ], 326 'lists' => [ 327 'buttons' => [ 328 'bullist', 329 'numlist', 330 ], 331 ], 332 'media' => [ 333 'buttons' => [ 334 'media', 335 ], 336 'menuitems' => [ 337 'media' => 'insert', 338 ], 339 ], 340 'nonbreaking' => [ 341 'buttons' => [ 342 'nonbreaking', 343 ], 344 'menuitems' => [ 345 'nonbreaking' => 'insert', 346 ], 347 ], 348 'pagebreak' => [ 349 'buttons' => [ 350 'pagebreak', 351 ], 352 'menuitems' => [ 353 'pagebreak' => 'insert', 354 ], 355 ], 356 'preview' => [ 357 'buttons' => [ 358 'preview', 359 ], 360 'menuitems' => [ 361 'preview' => 'file', 362 ], 363 ], 364 'quickbars' => [ 365 'buttons' => [ 366 'quickimage', 367 'quicklink', 368 'quicktable', 369 ], 370 ], 371 'save' => [ 372 'buttons' => [ 373 'cancel', 374 'save', 375 ], 376 ], 377 'searchreplace' => [ 378 'buttons' => [ 379 'searchreplace', 380 ], 381 'menuitems' => [ 382 'searchreplace' => 'edit', 383 ], 384 ], 385 'table' => [ 386 'buttons' => [ 387 'table', 388 'tablecellprops', 389 'tablecopyrow', 390 'tablecutrow', 391 'tabledelete', 392 'tabledeletecol', 393 'tabledeleterow', 394 'tableinsertdialog', 395 'tableinsertcolafter', 396 'tableinsertcolbefore', 397 'tableinsertrowafter', 398 'tableinsertrowbefore', 399 'tablemergecells', 400 'tablepasterowafter', 401 'tablepasterowbefore', 402 'tableprops', 403 'tablerowprops', 404 'tablesplitcells', 405 'tableclass', 406 'tablecellclass', 407 'tablecellvalign', 408 'tablecellborderwidth', 409 'tablecellborderstyle', 410 'tablecaption', 411 'tablecellbackgroundcolor', 412 'tablecellbordercolor', 413 'tablerowheader', 414 'tablecolheader', 415 ], 416 'menuitems' => [ 417 'inserttable' => 'table', 418 'tableprops' => 'table', 419 'deletetable' => 'table', 420 'cell' => 'table', 421 'tablemergecells' => 'table', 422 'tablesplitcells' => 'table', 423 'tablecellprops' => 'table', 424 'column' => 'table', 425 'tableinsertcolumnbefore' => 'table', 426 'tableinsertcolumnafter' => 'table', 427 'tablecutcolumn' => 'table', 428 'tablecopycolumn' => 'table', 429 'tablepastecolumnbefore' => 'table', 430 'tablepastecolumnafter' => 'table', 431 'tabledeletecolumn' => 'table', 432 'row' => 'table', 433 'tableinsertrowbefore' => 'table', 434 'tableinsertrowafter' => 'table', 435 'tablecutrow' => 'table', 436 'tablecopyrow' => 'table', 437 'tablepasterowbefore' => 'table', 438 'tablepasterowafter' => 'table', 439 'tablerowprops' => 'table', 440 'tabledeleterow' => 'table', 441 ], 442 ], 443 'template' => [ 444 'buttons' => [ 445 'template', 446 ], 447 'menuitems' => [ 448 'template' => 'insert', 449 ], 450 ], 451 'visualblocks' => [ 452 'buttons' => [ 453 'visualblocks', 454 ], 455 'menuitems' => [ 456 'visualblocks' => 'view', 457 ], 458 ], 459 'visualchars' => [ 460 'buttons' => [ 461 'visualchars', 462 ], 463 'menuitems' => [ 464 'visualchars' => 'view', 465 ], 466 ], 467 'wordcount' => [ 468 'buttons' => [ 469 'wordcount', 470 ], 471 'menuitems' => [ 472 'wordcount' => 'tools', 473 ], 474 ], 475 ]; 476 } 477 478 /** 479 * Get a list of the built-in TinyMCE plugins which we want to disable. 480 * 481 * These are usually disabled because we have replaced them, or they are not compatible with Moodle in some way. 482 * 483 * @return string[] 484 */ 485 protected function get_disabled_tinymce_plugins(): array { 486 return [ 487 // Disable the image and media plugins. 488 // These are not generally compatible with Moodle. 489 'image', 490 'media', 491 492 // Use the Moodle autosave plugin instead. 493 'autosave', 494 495 // Disable the Template plugin for now. 496 'template', 497 498 // Disable the preview plugin as it does not support Moodle filters. 499 'preview', 500 501 // Use the Moodle link plugin instead. 502 'link', 503 ]; 504 } 505 506 /** 507 * Get a list of the Moodle plugins with their button, and menuitem, configuration. 508 * 509 * @return array[] 510 */ 511 protected function get_moodle_plugins(): array { 512 $plugins = \core_component::get_plugin_list_with_class('tiny', 'plugininfo'); 513 514 $pluginconfig = []; 515 foreach ($plugins as $pluginname => $classname) { 516 if (!is_a($classname, plugin::class, true)) { 517 continue; 518 } 519 // Module name => [buttons, menuitems]. 520 $pluginconfig["{$pluginname}/plugin"] = $classname::get_plugin_info(); 521 } 522 523 return $pluginconfig; 524 } 525 526 /** 527 * Check whether premium plugins are configured and enabled. 528 * 529 * @return bool 530 */ 531 protected function premium_plugins_enabled(): bool { 532 return false; 533 } 534 535 /** 536 * Get a list of the Tiny Premium plugins with their button, and menuitem, configuration. 537 * 538 * Note: This only includes _compatible_ premium plugins. 539 * Some premium plugins *may not* be compatible with Moodle, and some may require additional configuration. 540 * 541 * @return array[] 542 */ 543 protected function get_premium_plugins(): array { 544 return [ 545 'a11ycheck' => [ 546 'buttons' => [ 547 'a11ycheck', 548 ], 549 'menuitems' => [ 550 'a11ycheck', 551 ], 552 ], 553 'advcode' => [ 554 'buttons' => [ 555 'code', 556 ], 557 'menuitems' => [ 558 'code', 559 ], 560 ], 561 'footnotes' => [ 562 'buttons' => [ 563 'footnotes', 564 'footnotesupdate', 565 ], 566 'menuitems' => [ 567 'footnotes', 568 'footnotesupdate', 569 ], 570 ], 571 'mergetags' => [ 572 'buttons' => [ 573 'mergetags', 574 ], 575 'menuitems' => [ 576 'mergetags', 577 ], 578 ], 579 'autocorrect' => [ 580 'menuitems' => [ 581 'autocorrect', 582 'capitalization', 583 ], 584 ], 585 ]; 586 } 587 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body