PageRenderTime 25ms CodeModel.GetById 25ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/editor/tinymce/classes/plugin.php

https://bitbucket.org/kudutest1/moodlegit
PHP | 442 lines | 190 code | 50 blank | 202 comment | 31 complexity | 3607618de4189a18a646e41875cb0520 MD5 | raw file
  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. defined('MOODLE_INTERNAL') || die();
  17. /**
  18. * TinyMCE text editor plugin base class.
  19. *
  20. * This is a base class for TinyMCE plugins implemented within Moodle. These
  21. * plugins can optionally provide new buttons/plugins within TinyMCE itself,
  22. * or configure the TinyMCE options.
  23. *
  24. * As well as overridable functions, other utility functions in this class
  25. * can be used when writing the plugins.
  26. *
  27. * Finally, a static function in this class is used to call into all the
  28. * plugins when required.
  29. *
  30. * @package editor_tinymce
  31. * @copyright 2012 The Open University
  32. * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  33. */
  34. abstract class editor_tinymce_plugin {
  35. /** @var string Plugin folder */
  36. protected $plugin;
  37. /** @var array Plugin settings */
  38. protected $config = null;
  39. /** @var array list of buttons defined by this plugin */
  40. protected $buttons = array();
  41. /**
  42. * @param string $plugin Name of folder
  43. */
  44. public function __construct($plugin) {
  45. $this->plugin = $plugin;
  46. }
  47. /**
  48. * Returns list of buttons defined by this plugin.
  49. * useful mostly as information when setting custom toolbar.
  50. *
  51. * @return array
  52. */
  53. public function get_buttons() {
  54. return $this->buttons;
  55. }
  56. /**
  57. * Makes sure config is loaded and cached.
  58. * @return void
  59. */
  60. protected function load_config() {
  61. if (!isset($this->config)) {
  62. $name = $this->get_name();
  63. $this->config = get_config("tinymce_$name");
  64. }
  65. }
  66. /**
  67. * Returns plugin config value.
  68. * @param string $name
  69. * @param string $default value if config does not exist yet
  70. * @return string value or default
  71. */
  72. public function get_config($name, $default = null) {
  73. $this->load_config();
  74. return isset($this->config->$name) ? $this->config->$name : $default;
  75. }
  76. /**
  77. * Sets plugin config value.
  78. * @param string $name name of config
  79. * @param string $value string config value, null means delete
  80. * @return string value
  81. */
  82. public function set_config($name, $value) {
  83. $pluginname = $this->get_name();
  84. $this->load_config();
  85. if ($value === null) {
  86. unset($this->config->$name);
  87. } else {
  88. $this->config->$name = $value;
  89. }
  90. set_config($name, $value, "tinymce_$pluginname");
  91. }
  92. /**
  93. * Returns name of this tinymce plugin.
  94. * @return string
  95. */
  96. public function get_name() {
  97. // All class names start with "tinymce_".
  98. $words = explode('_', get_class($this), 2);
  99. return $words[1];
  100. }
  101. /**
  102. * Adjusts TinyMCE init parameters for this plugin.
  103. *
  104. * Subclasses must implement this function in order to carry out changes
  105. * to the TinyMCE settings.
  106. *
  107. * @param array $params TinyMCE init parameters array
  108. * @param context $context Context where editor is being shown
  109. * @param array $options Options for this editor
  110. */
  111. protected abstract function update_init_params(array &$params, context $context,
  112. array $options = null);
  113. /**
  114. * Gets the order in which to run this plugin. Order usually only matters if
  115. * (a) the place you add your button might depend on another plugin, or
  116. * (b) you want to make some changes to layout etc. that should happen last.
  117. * The default order is 100; within that, plugins are sorted alphabetically.
  118. * Return a lower number if you want this plugin to run earlier, or a higher
  119. * number if you want it to run later.
  120. */
  121. protected function get_sort_order() {
  122. return 100;
  123. }
  124. /**
  125. * Adds a button to the editor, after another button (or at the end).
  126. *
  127. * Specify the location of this button using the $after variable. If you
  128. * leave this blank, the button will be added at the end.
  129. *
  130. * If you want to try different possible locations depending on existing
  131. * plugins you can set $alwaysadd to false and check the return value
  132. * to see if it succeeded.
  133. *
  134. * @param array $params TinyMCE init parameters array
  135. * @param int $row Row to add button to (1 to 3)
  136. * @param string $button Identifier of button/plugin
  137. * @param string $after Adds button directly after the named plugin
  138. * @param bool $alwaysadd If specified $after string not found, add at end
  139. * @return bool True if added
  140. */
  141. protected function add_button_after(array &$params, $row, $button,
  142. $after = '', $alwaysadd = true) {
  143. if ($this->is_button_present($params, $button)) {
  144. return true;
  145. }
  146. $row = $this->fix_row($params, $row);
  147. $field = 'theme_advanced_buttons' . $row;
  148. $old = $params[$field];
  149. // Empty = add at end.
  150. if ($after === '') {
  151. $params[$field] = $old . ',' . $button;
  152. return true;
  153. }
  154. // Try to add after given plugin.
  155. $params[$field] = preg_replace('~(,|^)(' . preg_quote($after) . ')(,|$)~',
  156. '$1$2,' . $button . '$3', $old);
  157. if ($params[$field] !== $old) {
  158. return true;
  159. }
  160. // If always adding, recurse to add it empty.
  161. if ($alwaysadd) {
  162. return $this->add_button_after($params, $row, $button);
  163. }
  164. // Otherwise return false (failed to add).
  165. return false;
  166. }
  167. /**
  168. * Adds a button to the editor.
  169. *
  170. * Specify the location of this button using the $before variable. If you
  171. * leave this blank, the button will be added at the start.
  172. *
  173. * If you want to try different possible locations depending on existing
  174. * plugins you can set $alwaysadd to false and check the return value
  175. * to see if it succeeded.
  176. *
  177. * @param array $params TinyMCE init parameters array
  178. * @param int $row Row to add button to (1 to 10)
  179. * @param string $button Identifier of button/plugin
  180. * @param string $before Adds button directly before the named plugin
  181. * @param bool $alwaysadd If specified $after string not found, add at start
  182. * @return bool True if added
  183. */
  184. protected function add_button_before(array &$params, $row, $button,
  185. $before = '', $alwaysadd = true) {
  186. if ($this->is_button_present($params, $button)) {
  187. return true;
  188. }
  189. $row = $this->fix_row($params, $row);
  190. $field = 'theme_advanced_buttons' . $row;
  191. $old = $params[$field];
  192. // Empty = add at start.
  193. if ($before === '') {
  194. $params[$field] = $button . ',' . $old;
  195. return true;
  196. }
  197. // Try to add after given plugin.
  198. $params[$field] = preg_replace('~(,|^)(' . preg_quote($before) . ')(,|$)~',
  199. '$1' . $button . ',$2$3', $old);
  200. if ($params[$field] !== $old) {
  201. return true;
  202. }
  203. // If always adding, recurse to add it empty.
  204. if ($alwaysadd) {
  205. return $this->add_button_before($params, $row, $button);
  206. }
  207. // Otherwise return false (failed to add).
  208. return false;
  209. }
  210. /**
  211. * Tests if button already present.
  212. * @param array $params
  213. * @param string $button
  214. * @return bool
  215. */
  216. private function is_button_present(array $params, $button) {
  217. for($i=1; $i<=10; $i++) {
  218. $field = 'theme_advanced_buttons' . $i;
  219. if (!isset($params[$field])) {
  220. continue;
  221. }
  222. $buttons = explode(',', $params[$field]);
  223. if (in_array($button, $buttons)) {
  224. return true;
  225. }
  226. }
  227. return false;
  228. }
  229. /**
  230. * Checks the row value is valid, fix if necessary.
  231. *
  232. * @param array $params TinyMCE init parameters array
  233. * @param int $row Row to add button if exists
  234. * @return int requested row if exists, lower number if does not exist.
  235. */
  236. private function fix_row(array &$params, $row) {
  237. $row = ($row < 1) ? 1 : (int)$row;
  238. $row = ($row > 10) ? 10 : $row;
  239. $field = 'theme_advanced_buttons' . $row;
  240. if (isset($params[$field])) {
  241. return $row;
  242. }
  243. for($i=$row; $i>=1; $i--) {
  244. if (isset($params[$field])) {
  245. return $row;
  246. }
  247. }
  248. // This should not happen.
  249. return 1;
  250. }
  251. /**
  252. * Adds a JavaScript plugin into TinyMCE. Note that adding a plugin does
  253. * not by itself add a button; you must do both.
  254. *
  255. * If you leave $pluginname blank (default) it uses the folder name.
  256. *
  257. * @param array $params TinyMCE init parameters array
  258. * @param string $pluginname Identifier for plugin within TinyMCE
  259. * @param string $jsfile Name of JS file (within plugin 'tinymce' directory)
  260. */
  261. protected function add_js_plugin(&$params, $pluginname='', $jsfile='editor_plugin.js') {
  262. global $CFG;
  263. // Set default plugin name.
  264. if ($pluginname === '') {
  265. $pluginname = $this->plugin;
  266. }
  267. // Add plugin to list in params, so it doesn't try to load it again.
  268. $params['plugins'] .= ',-' . $pluginname;
  269. // Add special param that causes Moodle TinyMCE init to load the plugin.
  270. if (!isset($params['moodle_init_plugins'])) {
  271. $params['moodle_init_plugins'] = '';
  272. } else {
  273. $params['moodle_init_plugins'] .= ',';
  274. }
  275. // Get URL of main JS file and store in params.
  276. $jsurl = $this->get_tinymce_file_url($jsfile, false);
  277. $params['moodle_init_plugins'] .= $pluginname . ':' . $jsurl;
  278. }
  279. /**
  280. * Returns URL to files in the TinyMCE folder within this plugin, suitable
  281. * for client-side use such as loading JavaScript files. (This URL normally
  282. * goes through loader.php and contains the plugin version to ensure
  283. * correct and long-term cacheing.)
  284. *
  285. * @param string $file Filename or path within the folder
  286. * @param bool $absolute Set false to get relative URL from plugins folder
  287. */
  288. public function get_tinymce_file_url($file='', $absolute=true) {
  289. global $CFG;
  290. // Version number comes from plugin version.php, except in developer
  291. // mode where the special string 'dev' is used (prevents cacheing and
  292. // serves unminified JS).
  293. if (debugging('', DEBUG_DEVELOPER)) {
  294. $version = '-1';
  295. } else {
  296. $version = $this->get_version();
  297. }
  298. // Calculate the JS url (relative to the TinyMCE plugins folder - using
  299. // relative URL saves a few bytes in each HTML page).
  300. if ($CFG->slasharguments) {
  301. // URL is usually from loader.php...
  302. $jsurl = 'loader.php/' . $this->plugin . '/' . $version . '/' . $file;
  303. } else {
  304. // ...except when slash arguments are turned off it serves direct.
  305. // In this situation there is no version details and it is up to
  306. // the browser and server to negotiate cacheing, which will mean
  307. // requesting the JS files frequently (reduced performance).
  308. $jsurl = $this->plugin . '/tinymce/' . $file;
  309. }
  310. if ($absolute) {
  311. $jsurl = $CFG->wwwroot . '/lib/editor/tinymce/plugins/' . $jsurl;
  312. }
  313. return $jsurl;
  314. }
  315. /**
  316. * Obtains version number from version.php for this plugin.
  317. *
  318. * @return string Version number
  319. */
  320. protected function get_version() {
  321. global $CFG;
  322. $plugin = new stdClass;
  323. require($CFG->dirroot . '/lib/editor/tinymce/plugins/' . $this->plugin . '/version.php');
  324. return $plugin->version;
  325. }
  326. /**
  327. * Calls all available plugins to adjust the TinyMCE init parameters.
  328. *
  329. * @param array $params TinyMCE init parameters array
  330. * @param context $context Context where editor is being shown
  331. * @param array $options Options for this editor
  332. */
  333. public static function all_update_init_params(array &$params,
  334. context $context, array $options = null) {
  335. global $CFG;
  336. // Get list of plugin directories.
  337. $plugins = get_plugin_list('tinymce');
  338. // Get list of disabled subplugins.
  339. $disabled = array();
  340. if ($params['moodle_config']->disabledsubplugins) {
  341. foreach (explode(',', $params['moodle_config']->disabledsubplugins) as $sp) {
  342. $sp = trim($sp);
  343. if ($sp !== '') {
  344. $disabled[$sp] = $sp;
  345. }
  346. }
  347. }
  348. // Construct all the plugins.
  349. $pluginobjects = array();
  350. foreach ($plugins as $plugin => $dir) {
  351. if (isset($disabled[$plugin])) {
  352. continue;
  353. }
  354. require_once($dir . '/lib.php');
  355. $classname = 'tinymce_' . $plugin;
  356. $pluginobjects[] = new $classname($plugin);
  357. }
  358. // Sort plugins by sort order and name.
  359. usort($pluginobjects, array('editor_tinymce_plugin', 'compare_plugins'));
  360. // Run the function for each plugin.
  361. foreach ($pluginobjects as $obj) {
  362. $obj->update_init_params($params, $context, $options);
  363. }
  364. }
  365. /**
  366. * Gets a named plugin object. Will cause fatal error if plugin doesn't exist.
  367. *
  368. * @param string $plugin Name of plugin e.g. 'moodleemoticon'
  369. * @return editor_tinymce_plugin Plugin object
  370. */
  371. public static function get($plugin) {
  372. $dir = get_component_directory('tinymce_' . $plugin);
  373. require_once($dir . '/lib.php');
  374. $classname = 'tinymce_' . $plugin;
  375. return new $classname($plugin);
  376. }
  377. /**
  378. * Compares two plugins.
  379. * @param editor_tinymce_plugin $a
  380. * @param editor_tinymce_plugin $b
  381. * @return Negative number if $a is before $b
  382. */
  383. public static function compare_plugins(editor_tinymce_plugin $a, editor_tinymce_plugin $b) {
  384. // Use sort order first.
  385. $order = $a->get_sort_order() - $b->get_sort_order();
  386. if ($order != 0) {
  387. return $order;
  388. }
  389. // Then sort alphabetically.
  390. return strcmp($a->plugin, $b->plugin);
  391. }
  392. }