See Release Notes
Long Term Support Release
<?php // This file is part of Moodle - http://moodle.org/ // // Moodle is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Moodle is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Moodle. If not, see <http://www.gnu.org/licenses/>. namespace editor_tiny; /** * Tiny Editor. * * @package editor_tiny * @copyright 2021 Andrew Lyons <andrew@nicols.co.uk> * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class editor extends \texteditor { /** @var manager The Tiny Manager instace */ protected $manager; /** @var \stdClass|null The default configuration to use if none is provided */ protected static $defaultconfiguration = null; /** * Instantiate the new editor instance. */ public function __construct() { $this->manager = new manager(); } /** * Set the default configuration for the editor. * * @param manager $manager The editor manager */ public static function set_default_configuration(manager $manager): void { global $PAGE; if (self::is_default_configuration_set()) { return; } $context = $PAGE->context; $config = (object) [ 'css' => $PAGE->theme->editor_css_url()->out(false), 'context' => $context->id, 'plugins' => $manager->get_plugin_configuration($context, [], []), ]; $config = json_encode($config); $inlinejs = <<<EOF M.util.js_pending('editor_tiny/editor:defaultConfiguration'); require(['editor_tiny/editor'], (Tiny) => { Tiny.configureDefaultEditor({$config}); M.util.js_complete('editor_tiny/editor:defaultConfiguration'); }); EOF; $PAGE->requires->js_amd_inline($inlinejs); self::$defaultconfiguration = $config; } /** * Fetch the current defautl configuration. * * @return \stdClass|null The default configuration or null if not set. */ public static function get_default_configuration(): ?\stdClass { return self::$defaultconfiguration; } /** * Reset the default configuration. */ public static function reset_default_configuration(): void { self::$defaultconfiguration = null; } /** * Check if the default configuration is set. * * @return bool True if the default configuration is set. */ public static function is_default_configuration_set(): bool { return !empty(self::$defaultconfiguration); } /** * Is the current browser supported by this editor? * * @return bool */ public function supported_by_browser() { return true; } /** * List of supported text field formats. * * @return array */ public function get_supported_formats() { return [ FORMAT_HTML => FORMAT_HTML, ]; } /** * Returns text format preferred by this editor. * * @return int */ public function get_preferred_format() { return FORMAT_HTML; } /** * Does this editor support picking from repositories? * * @return bool */ public function supports_repositories() { return true; } /** * Use this editor for given element. * * @param string $elementid * @param array $options * @param null $fpoptions */ public function use_editor($elementid, array $options = null, $fpoptions = null) { global $PAGE; // Ensure that the default configuration is set. self::set_default_configuration($this->manager); if ($fpoptions === null) { $fpoptions = []; } $context = $PAGE->context; if (isset($options['context']) && ($options['context'] instanceof \context)) { // A different context was provided. // Use that instead. $context = $options['context']; } // Generate the configuration for this editor. $siteconfig = get_config('editor_tiny'); $config = (object) [ // The URL to the CSS file for the editor. 'css' => $PAGE->theme->editor_css_url()->out(false), // The current context for this page or editor. 'context' => $context->id, // File picker options. 'filepicker' => $fpoptions, 'currentLanguage' => current_language(), 'branding' => property_exists($siteconfig, 'branding') ? !empty($siteconfig->branding) : true, // Language options. 'language' => [ 'currentlang' => current_language(), 'installed' => get_string_manager()->get_list_of_translations(true), 'available' => get_string_manager()->get_list_of_languages() ], // Placeholder selectors. // Some contents (Example: placeholder elements) are only shown in the editor, and not to users. It is unrelated to the // real display. We created a list of placeholder selectors, so we can decide to or not to apply rules, styles... to // these elements. // The default of this list will be empty. // Other plugins can register their placeholder elements to placeholderSelectors list by calling // editor_tiny/options::registerPlaceholderSelectors. 'placeholderSelectors' => [], // Plugin configuration. 'plugins' => $this->manager->get_plugin_configuration($context, $options, $fpoptions, $this), // Nest menu inside parent DOM. 'nestedmenu' => true, ]; if (defined('BEHAT_SITE_RUNNING') && BEHAT_SITE_RUNNING) { // Add sample selectors for Behat test. $config->placeholderSelectors = ['.behat-tinymce-placeholder']; } foreach ($fpoptions as $fp) { // Guess the draftitemid for the editor. // Note: This is the best we can do at the moment. if (!empty($fp->itemid)) { $config->draftitemid = $fp->itemid; break; } } $configoptions = json_encode(convert_to_array($config)); // Note: This is not ideal but the editor does not have control over any HTML output. // The Editor API only allows you to run JavaScript. // In the future we will extend the editor API to allow it to generate the textarea, or attributes to use in the // textarea or its wrapper. // For now we cannot use the `js_call_amd()` API call because it warns if the parameters passed exceed a // relatively low character limit. $config = json_encode($config); $inlinejs = <<<EOF M.util.js_pending('editor_tiny/editor'); require(['editor_tiny/editor'], (Tiny) => { Tiny.setupForElementId({< elementId: "${elementid}", < options: ${configoptions},> elementId: "{$elementid}", > options: {$configoptions},}); M.util.js_complete('editor_tiny/editor'); }); EOF; $PAGE->requires->js_amd_inline($inlinejs); } }