Permalink
Browse files

MDL-33041 (3) TinyMCE: Support custom plugins

  • Loading branch information...
1 parent 1702fb6 commit fae911708e696bf468ff0447bd47523004a87ccc @sammarshallou sammarshallou committed with skodak May 16, 2012
@@ -0,0 +1,323 @@
+<?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/>.
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * TinyMCE text editor plugin base class.
+ *
+ * This is a base class for TinyMCE plugins implemented within Moodle. These
+ * plugins can optionally provide new buttons/plugins within TinyMCE itself,
+ * or configure the TinyMCE options.
+ *
+ * As well as overridable functions, other utility functions in this class
+ * can be used when writing the plugins.
+ *
+ * Finally, a static function in this class is used to call into all the
+ * plugins when required.
+ *
+ * @package editor_tinymce
+ * @copyright 2012 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+abstract class editor_tinymce_plugin {
+ /** @var string Plugin folder */
+ protected $plugin;
+
+ /**
+ * @param string $plugin Name of folder
+ */
+ public function __construct($plugin) {
+ $this->plugin = $plugin;
+ }
+
+ /**
+ * Adjusts TinyMCE init parameters for this plugin.
+ *
+ * Subclasses must implement this function in order to carry out changes
+ * to the TinyMCE settings.
+ *
+ * @param array $params TinyMCE init parameters array
+ * @param context $context Context where editor is being shown
+ * @param array $options Options for this editor
+ */
+ protected abstract function update_init_params(array &$params, context $context,
+ array $options = null);
+
+ /**
+ * Gets the order in which to run this plugin. Order usually only matters if
+ * (a) the place you add your button might depend on another plugin, or
+ * (b) you want to make some changes to layout etc. that should happen last.
+ * The default order is 100; within that, plugins are sorted alphabetically.
+ * Return a lower number if you want this plugin to run earlier, or a higher
+ * number if you want it to run later.
+ */
+ protected function get_sort_order() {
+ return 100;
+ }
+
+ /**
+ * Adds a button to the editor, after another button (or at the end).
+ *
+ * Specify the location of this button using the $after variable. If you
+ * leave this blank, the button will be added at the end.
+ *
+ * If you want to try different possible locations depending on existing
+ * plugins you can set $alwaysadd to false and check the return value
+ * to see if it succeeded.
+ *
+ * @param array $params TinyMCE init parameters array
+ * @param int $row Row to add button to (1 to 3)
+ * @param string $button Identifier of button/plugin
+ * @param string $after Adds button directly after the named plugin
+ * @param bool $alwaysadd If specified $after string not found, add at end
+ * @return bool True if added
+ */
+ protected function add_button_after(array &$params, $row, $button,
+ $after = '', $alwaysadd = true) {
+ $this->check_row($row);
+
+ $field = 'theme_advanced_buttons' . $row;
+ $old = $params[$field];
+
+ // Empty = add at end.
+ if ($after === '') {
+ $params[$field] = $old . ',' . $button;
+ return true;
+ }
+
+ // Try to add after given plugin.
+ $params[$field] = preg_replace('~(,|^)(' . preg_quote($after) . ')(,|$)~',
+ '$1$2,' . $button . '$3', $old);
+ if ($params[$field] !== $old) {
+ return true;
+ }
+
+ // If always adding, recurse to add it empty.
+ if ($alwaysadd) {
+ return $this->add_button_after($params, $row, $button);
+ }
+
+ // Otherwise return false (failed to add).
+ return false;
+ }
+
+ /**
+ * Adds a button to the editor.
+ *
+ * Specify the location of this button using the $before variable. If you
+ * leave this blank, the button will be added at the start.
+ *
+ * If you want to try different possible locations depending on existing
+ * plugins you can set $alwaysadd to false and check the return value
+ * to see if it succeeded.
+ *
+ * @param array $params TinyMCE init parameters array
+ * @param int $row Row to add button to (1 to 3)
+ * @param string $button Identifier of button/plugin
+ * @param string $before Adds button directly before the named plugin
+ * @param bool $alwaysadd If specified $after string not found, add at start
+ * @return bool True if added
+ */
+ protected function add_button_before(array &$params, $row, $button,
+ $before = '', $alwaysadd = true) {
+ $this->check_row($row);
+
+ $field = 'theme_advanced_buttons' . $row;
+ $old = $params[$field];
+
+ // Empty = add at start.
+ if ($before === '') {
+ $params[$field] = $button . ',' . $old;
+ return true;
+ }
+
+ // Try to add after given plugin.
+ $params[$field] = preg_replace('~(,|^)(' . preg_quote($before) . ')(,|$)~',
+ '$1' . $button . ',$2$3', $old);
+ if ($params[$field] !== $old) {
+ return true;
+ }
+
+ // If always adding, recurse to add it empty.
+ if ($alwaysadd) {
+ return $this->add_button_before($params, $row, $button);
+ }
+
+ // Otherwise return false (failed to add).
+ return false;
+ }
+
+ /**
+ * Checks the row value is valid.
+ *
+ * @param int $row Row to add button to (1 to 3)
+ * @throws coding_exception If row value is outside the range 1-3
+ */
+ private function check_row($row) {
+ if ($row < 1 || $row > 3) {
+ throw new coding_exception("Invalid row option: $row");
+ }
+ }
+
+ /**
+ * Adds a JavaScript plugin into TinyMCE. Note that adding a plugin does
+ * not by itself add a button; you must do both.
+ *
+ * If you leave $pluginname blank (default) it uses the folder name.
+ *
+ * @param array $params TinyMCE init parameters array
+ * @param string $pluginname Identifier for plugin within TinyMCE
+ * @param string $jsfile Name of JS file (within plugin 'tinymce' directory)
+ */
+ protected function add_js_plugin(&$params, $pluginname='', $jsfile='editor_plugin.js') {
+ global $CFG;
+
+ // Set default plugin name.
+ if ($pluginname === '') {
+ $pluginname = $this->plugin;
+ }
+
+ // Add plugin to list in params, so it doesn't try to load it again.
+ $params['plugins'] .= ',-' . $pluginname;
+
+ // Add special param that causes Moodle TinyMCE init to load the plugin.
+ if (!isset($params['moodle_init_plugins'])) {
+ $params['moodle_init_plugins'] = '';
+ } else {
+ $params['moodle_init_plugins'] .= ',';
+ }
+
+ // Get URL of main JS file and store in params.
+ $jsurl = $this->get_tinymce_file_url($jsfile, false);
+ $params['moodle_init_plugins'] .= $pluginname . ':' . $jsurl;
+ }
+
+ /**
+ * Returns URL to files in the TinyMCE folder within this plugin, suitable
+ * for client-side use such as loading JavaScript files. (This URL normally
+ * goes through loader.php and contains the plugin version to ensure
+ * correct and long-term cacheing.)
+ *
+ * @param string $file Filename or path within the folder
+ * @param bool $absolute Set false to get relative URL from plugins folder
+ */
+ public function get_tinymce_file_url($file='', $absolute=true) {
+ global $CFG;
+
+ // Version number comes from plugin version.php, except in developer
+ // mode where the special string 'dev' is used (prevents cacheing and
+ // serves unminified JS).
+ if (debugging('', DEBUG_DEVELOPER)) {
+ $version = '-1';
+ } else {
+ $version = $this->get_version();
+ }
+
+ // Calculate the JS url (relative to the TinyMCE plugins folder - using
+ // relative URL saves a few bytes in each HTML page).
+ if ($CFG->slasharguments) {
+ // URL is usually from loader.php...
+ $jsurl = 'loader.php/' . $this->plugin . '/' . $version . '/' . $file;
+ } else {
+ // ...except when slash arguments are turned off it serves direct.
+ // In this situation there is no version details and it is up to
+ // the browser and server to negotiate cacheing, which will mean
+ // requesting the JS files frequently (reduced performance).
+ $jsurl = $this->plugin . '/tinymce/' . $file;
+ }
+
+ if ($absolute) {
+ $jsurl = $CFG->wwwroot . '/lib/editor/tinymce/plugins/' . $jsurl;
+ }
+
+ return $jsurl;
+ }
+
+ /**
+ * Obtains version number from version.php for this plugin.
+ *
+ * @return string Version number
+ */
+ protected function get_version() {
+ global $CFG;
+
+ $plugin = new stdClass;
+ require($CFG->dirroot . '/lib/editor/tinymce/plugins/' . $this->plugin . '/version.php');
+ return $plugin->version;
+ }
+
+ /**
+ * Calls all available plugins to adjust the TinyMCE init parameters.
+ *
+ * @param array $params TinyMCE init parameters array
+ * @param context $context Context where editor is being shown
+ * @param array $options Options for this editor
+ */
+ public static function all_update_init_params(array &$params,
+ context $context, array $options = null) {
+ global $CFG;
+
+ // Get list of plugin directories.
+ $plugins = get_plugin_list('tinymce');
+
+ // Construct all the plugins.
+ $pluginobjects = array();
+ foreach ($plugins as $plugin => $dir) {
+ require_once($dir . '/lib.php');
+ $classname = 'tinymce_' . $plugin;
+ $pluginobjects[] = new $classname($plugin);
+ }
+
+ // Sort plugins by sort order and name.
+ usort($pluginobjects, array('editor_tinymce_plugin', 'compare_plugins'));
+
+ // Run the function for each plugin.
+ foreach ($pluginobjects as $obj) {
+ $obj->update_init_params($params, $context, $options);
+ }
+ }
+
+ /**
+ * Gets a named plugin object. Will cause fatal error if plugin doesn't exist.
+ *
+ * @param string $plugin Name of plugin e.g. 'moodleemoticon'
+ * @return editor_tinymce_plugin Plugin object
+ */
+ public static function get($plugin) {
+ $dir = get_component_directory('tinymce_' . $plugin);
+ require_once($dir . '/lib.php');
+ $classname = 'tinymce_' . $plugin;
+ return new $classname($plugin);
+ }
+
+ /**
+ * Compares two plugins.
+ * @param editor_tinymce_plugin $a
+ * @param editor_tinymce_plugin $b
+ * @return Negative number if $a is before $b
+ */
+ public static function compare_plugins(editor_tinymce_plugin $a, editor_tinymce_plugin $b) {
+ // Use sort order first.
+ $order = $a->get_sort_order() - $b->get_sort_order();
+ if ($order != 0) {
+ return $order;
+ }
+
+ // Then sort alphabetically.
+ return strcmp($a->plugin, $b->plugin);
+ }
+}
@@ -0,0 +1,27 @@
+<?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/>.
+
+/**
+ * TinyMCE subplugin type declaration.
+ *
+ * @package editor_tinymce
+ * @copyright 2012 The Open University
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$subplugins = array('tinymce' => 'lib/editor/tinymce/plugins');
@@ -51,6 +51,23 @@
$result[$parts[0]][$parts[1]] = $value;
}
+// Add subplugin strings. These automatically are added under the plugin name
+// unless they include a colon, in which case they are treated same as the
+// main lang file strings. (Just in case you have a single Moodle plugin
+// creating multiple tinymce plugins.)
+foreach (get_plugin_list('tinymce') as $component => $ignored) {
+ $componentstrings = get_string_manager()->load_component_strings(
+ 'tinymce_' . $component, $lang);
+ foreach ($componentstrings as $key => $value) {
+ $parts = explode(':', $key);
+ if (count($parts) == 2) {
+ $result[$parts[0]][$parts[1]] = $value;
+ } else {
+ $result[$component][$key] = $value;
+ }
+ }
+}
+
$output = 'tinyMCE.addI18n({'.$lang.':'.json_encode($result).'});';
$lifetime = '10'; // TODO: increase later
Oops, something went wrong.

0 comments on commit fae9117

Please sign in to comment.