Search moodle.org's
Developer Documentation

  • Bug fixes for general core bugs in 3.11.x will end 9 May 2022 (12 months).
  • Bug fixes for security issues in 3.11.x will end 14 November 2022 (18 months).
  • PHP version: minimum PHP 7.3.0 Note: minimum PHP version has increased since Moodle 3.10. PHP 7.4.x is supported too.
  •    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  /**
      18   * TinyMCE text editor integration.
      19   *
      20   * @package    editor
      21   * @subpackage tinymce
      22   * @copyright  2009 Petr Skoda (http://skodak.org)
      23   * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      24   */
      25  
      26  defined('MOODLE_INTERNAL') || die();
      27  
      28  class tinymce_texteditor extends texteditor {
      29      /** @var string active version - this is the directory name where to find tinymce code */
      30      public $version = '3.5.11';
      31  
      32      /**
      33       * Is the current browser supported by this editor?
      34       * @return bool
      35       */
      36      public function supported_by_browser() {
      37          // We don't support any browsers which it doesn't support.
      38          return true;
      39      }
      40  
      41      /**
      42       * Returns array of supported text formats.
      43       * @return array
      44       */
      45      public function get_supported_formats() {
      46          // FORMAT_MOODLE is not supported here, sorry.
      47          return array(FORMAT_HTML => FORMAT_HTML);
      48      }
      49  
      50      /**
      51       * Returns text format preferred by this editor.
      52       * @return int
      53       */
      54      public function get_preferred_format() {
      55          return FORMAT_HTML;
      56      }
      57  
      58      /**
      59       * Does this editor support picking from repositories?
      60       * @return bool
      61       */
      62      public function supports_repositories() {
      63          return true;
      64      }
      65  
      66      /**
      67       * Sets up head code if necessary.
      68       */
      69      public function head_setup() {
      70      }
      71  
      72      /**
      73       * Use this editor for give element.
      74       *
      75       * @param string $elementid
      76       * @param array $options
      77       * @param null $fpoptions
      78       */
      79      public function use_editor($elementid, array $options=null, $fpoptions=null) {
      80          global $PAGE, $CFG;
      81          // Note: use full moodle_url instance to prevent standard JS loader, make sure we are using https on profile page if required.
      82          if ($CFG->debugdeveloper) {
      83              $PAGE->requires->js(new moodle_url('/lib/editor/tinymce/tiny_mce/'.$this->version.'/tiny_mce_src.js'));
      84          } else {
      85              $PAGE->requires->js(new moodle_url('/lib/editor/tinymce/tiny_mce/'.$this->version.'/tiny_mce.js'));
      86          }
      87          $PAGE->requires->js_init_call('M.editor_tinymce.init_editor', array($elementid, $this->get_init_params($elementid, $options)), true);
      88          if ($fpoptions) {
      89              $PAGE->requires->js_init_call('M.editor_tinymce.init_filepicker', array($elementid, $fpoptions), true);
      90          }
      91      }
      92  
      93      protected function get_init_params($elementid, array $options=null) {
      94          global $CFG, $PAGE, $OUTPUT;
      95  
      96          //TODO: we need to implement user preferences that affect the editor setup too
      97  
      98          $directionality = get_string('thisdirection', 'langconfig');
      99          $strtime        = get_string('strftimetime');
     100          $strdate        = get_string('strftimedaydate');
     101          $lang           = current_language();
     102          $contentcss     = $PAGE->theme->editor_css_url()->out(false);
     103  
     104          $context = empty($options['context']) ? context_system::instance() : $options['context'];
     105  
     106          $config = get_config('editor_tinymce');
     107          if (!isset($config->disabledsubplugins)) {
     108              $config->disabledsubplugins = '';
     109          }
     110  
     111          // Remove the manage files button if requested.
     112          if (isset($options['enable_filemanagement']) && !$options['enable_filemanagement']) {
     113              if (!strpos($config->disabledsubplugins, 'managefiles')) {
     114                  $config->disabledsubplugins .= ',managefiles';
     115              }
     116          }
     117  
     118          $fontselectlist = empty($config->fontselectlist) ? '' : $config->fontselectlist;
     119  
     120          $langrev = -1;
     121          if (!empty($CFG->cachejs)) {
     122              $langrev = get_string_manager()->get_revision();
     123          }
     124  
     125          $params = array(
     126              'moodle_config' => $config,
     127              'mode' => "exact",
     128              'elements' => $elementid,
     129              'relative_urls' => false,
     130              'document_base_url' => $CFG->wwwroot,
     131              'moodle_plugin_base' => "$CFG->wwwroot/lib/editor/tinymce/plugins/",
     132              'content_css' => $contentcss,
     133              'language' => $lang,
     134              'directionality' => $directionality,
     135              'plugin_insertdate_dateFormat ' => $strdate,
     136              'plugin_insertdate_timeFormat ' => $strtime,
     137              'theme' => "advanced",
     138              'skin' => "moodle",
     139              'apply_source_formatting' => true,
     140              'remove_script_host' => false,
     141              'entity_encoding' => "raw",
     142              'plugins' => 'lists,table,style,layer,advhr,advlink,emotions,inlinepopups,' .
     143                  'searchreplace,paste,directionality,fullscreen,nonbreaking,contextmenu,' .
     144                  'insertdatetime,save,iespell,preview,print,noneditable,visualchars,' .
     145                  'xhtmlxtras,template,pagebreak',
     146              'gecko_spellcheck' => true,
     147              'theme_advanced_font_sizes' => "1,2,3,4,5,6,7",
     148              'theme_advanced_layout_manager' => "SimpleLayout",
     149              'theme_advanced_toolbar_align' => "left",
     150              'theme_advanced_fonts' => $fontselectlist,
     151              'theme_advanced_resize_horizontal' => true,
     152              'theme_advanced_resizing' => true,
     153              'theme_advanced_resizing_min_height' => 30,
     154              'min_height' => 30,
     155              'theme_advanced_toolbar_location' => "top",
     156              'theme_advanced_statusbar_location' => "bottom",
     157              'language_load' => false, // We load all lang strings directly from Moodle.
     158              'langrev' => $langrev,
     159          );
     160  
     161          // Should we override the default toolbar layout unconditionally?
     162          if (!empty($config->customtoolbar) and $customtoolbar = self::parse_toolbar_setting($config->customtoolbar)) {
     163              $i = 1;
     164              foreach ($customtoolbar as $line) {
     165                  $params['theme_advanced_buttons'.$i] = $line;
     166                  $i++;
     167              }
     168          } else {
     169              // At least one line is required.
     170              $params['theme_advanced_buttons1'] = '';
     171          }
     172  
     173          if (!empty($config->customconfig)) {
     174              $config->customconfig = trim($config->customconfig);
     175              $decoded = json_decode($config->customconfig, true);
     176              if (is_array($decoded)) {
     177                  foreach ($decoded as $k=>$v) {
     178                      $params[$k] = $v;
     179                  }
     180              }
     181          }
     182  
     183          if (!empty($options['legacy']) or !empty($options['noclean']) or !empty($options['trusted'])) {
     184              // now deal somehow with non-standard tags, people scream when we do not make moodle code xtml strict,
     185              // but they scream even more when we strip all tags that are not strict :-(
     186              $params['valid_elements'] = 'script[src|type],*[*]'; // for some reason the *[*] does not inlcude javascript src attribute MDL-25836
     187              $params['invalid_elements'] = '';
     188          }
     189          // Add unique moodle elements - unfortunately we have to decide if these are SPANs or DIVs.
     190          $params['extended_valid_elements'] = 'nolink,tex,algebra,lang[lang]';
     191          $params['custom_elements'] = 'nolink,~tex,~algebra,lang';
     192  
     193          //Add onblur event for client side text validation
     194          if (!empty($options['required'])) {
     195              $params['init_instance_callback'] = 'M.editor_tinymce.onblur_event';
     196          }
     197  
     198          // Allow plugins to adjust parameters.
     199          editor_tinymce_plugin::all_update_init_params($params, $context, $options);
     200  
     201          // Remove temporary parameters.
     202          unset($params['moodle_config']);
     203  
     204          return $params;
     205      }
     206  
     207      /**
     208       * Parse the custom toolbar setting.
     209       * @param string $customtoolbar
     210       * @return array csv toolbar lines
     211       */
     212      public static function parse_toolbar_setting($customtoolbar) {
     213          $result = array();
     214          $customtoolbar = trim($customtoolbar);
     215          if ($customtoolbar === '') {
     216              return $result;
     217          }
     218          $customtoolbar = str_replace("\r", "\n", $customtoolbar);
     219          $customtoolbar = strtolower($customtoolbar);
     220          $i = 0;
     221          foreach (explode("\n", $customtoolbar) as $line) {
     222              $line = preg_replace('/[^a-z0-9_,\|\-]/', ',', $line);
     223              $line = str_replace('|', ',|,', $line);
     224              $line = preg_replace('/,,+/', ',', $line);
     225              $line = trim($line, ',|');
     226              if ($line === '') {
     227                  continue;
     228              }
     229              if ($i == 10) {
     230                  // Maximum is ten lines, merge the rest to the last line.
     231                  $result[9] = $result[9].','.$line;
     232              } else {
     233                  $result[] = $line;
     234                  $i++;
     235              }
     236          }
     237          return $result;
     238      }
     239  
     240      /**
     241       * Gets a named plugin object. Will cause fatal error if plugin doesn't
     242       * exist. This is intended for use by plugin files themselves.
     243       *
     244       * @param string $plugin Name of plugin e.g. 'moodleemoticon'
     245       * @return editor_tinymce_plugin Plugin object
     246       */
     247      public function get_plugin($plugin) {
     248          global $CFG;
     249          return editor_tinymce_plugin::get($plugin);
     250      }
     251  
     252      /**
     253       * Equivalent to tinyMCE.baseURL value available from JavaScript,
     254       * always use instead of /../ when referencing tinymce core code from moodle plugins!
     255       *
     256       * @return moodle_url url pointing to the root of TinyMCE javascript code.
     257       */
     258      public function get_tinymce_base_url() {
     259          global $CFG;
     260          return new moodle_url("/lib/editor/tinymce/tiny_mce/$this->version/");
     261      }
     262  
     263  }