Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

MDL-32750 Question: make the html editor tools collapsible

  • Loading branch information...
commit 2a22be64ee8129912c44f28b977c05143231736f 1 parent b3778a0
Colin Chambers authored
2  lang/en/form.php
@@ -41,6 +41,7 @@
41 41 $string['err_required'] = 'You must supply a value here.';
42 42 $string['general'] = 'General';
43 43 $string['hideadvanced'] = 'Hide advanced';
  44 +$string['hideeditortoolbar'] = 'Hide editing tools';
44 45 $string['hour'] = 'Hour';
45 46 $string['minute'] = 'Minute';
46 47 $string['miscellaneoussettings'] = 'Miscellaneous settings';
@@ -57,6 +58,7 @@
57 58 $string['selectallornone'] = 'Select all/none';
58 59 $string['selected'] = 'Selected';
59 60 $string['showadvanced'] = 'Show advanced';
  61 +$string['showeditortoolbar'] = 'Show editing tools';
60 62 $string['somefieldsrequired'] = 'There are required fields in this form marked {$a}.';
61 63 $string['time'] = 'Time';
62 64 $string['timeunit'] = 'Time unit';
0  lib/editor/tinymce/editor_styles.css
No changes.
24 lib/editor/tinymce/lib.php
@@ -106,6 +106,7 @@ public function use_editor($elementid, array $options=null, $fpoptions=null) {
106 106 if ($fpoptions) {
107 107 $PAGE->requires->js_init_call('M.editor_tinymce.init_filepicker', array($elementid, $fpoptions), true);
108 108 }
  109 + $this->initialise_collapse_js();
109 110 }
110 111
111 112 protected function get_init_params($elementid, array $options=null) {
@@ -274,4 +275,27 @@ public function get_tinymce_base_url() {
274 275 global $CFG;
275 276 return new moodle_url("$CFG->httpswwwroot/lib/editor/tinymce/tiny_mce/$this->version/");
276 277 }
  278 +
  279 + /**
  280 + * Initialise javascript form elements
  281 + * @return void
  282 + */
  283 + public function initialise_collapse_js() {
  284 + global $CFG, $PAGE, $OUTPUT;
  285 +
  286 + // This method is called for every editor instance. Ensure it's only run once.
  287 + // Static is a clunky solution but the best we could find to keep everything simple and encapsulated.
  288 + static $is_initialised;
  289 +
  290 + if ($is_initialised) {
  291 + return;
  292 + }
  293 +
  294 + // Initialise language strings.
  295 + $PAGE->requires->strings_for_js(array('hideeditortoolbar', 'showeditortoolbar'),
  296 + 'form');
  297 +
  298 + $PAGE->requires->yui_module('moodle-editor_tinymce-collapse', 'M.editor_collapse.init');
  299 + $is_initialised = true;
  300 + }
277 301 }
3  lib/editor/tinymce/styles.css
... ... @@ -0,0 +1,3 @@
  1 +.mform .felement.feditor .toggle_editor_toolbar {background: #EEEEEE;border-color: #BBBBBB;border-radius: 4px 4px 0 0;border-style: solid solid none;border-width: 1px 1px 0;display: inline-block;font-size: 0.7em;padding: 3px 6px;width: 9em;}
  2 +.mform .felement.feditor .mceStatusbar,
  3 +.mform .felement.feditor iframe {min-width: 35em;}
166 lib/editor/tinymce/yui/collapse/collapse.js
... ... @@ -0,0 +1,166 @@
  1 +YUI.add('moodle-editor_tinymce-collapse', function(Y) {
  2 +
  3 + var COLLAPSE = function() {
  4 + COLLAPSE.superclass.constructor.apply(this, arguments);
  5 + };
  6 +
  7 + Y.extend(COLLAPSE, Y.Base, {
  8 +
  9 + toggleNodeTemplate : null,
  10 + /**
  11 + * Set up basic values for static access.
  12 + */
  13 + init : function() {
  14 + this.initialise_toggles(10);
  15 + },
  16 +
  17 + /**
  18 + * Has TinyMCE been loaded and the editors been initialised?
  19 + * Designed mainly for IE
  20 + * @return bool
  21 + */
  22 + editors_initialised : function() {
  23 + return typeof tinyMCE !== 'undefined';
  24 + },
  25 +
  26 + initialise_toggles : function(refreshes) {
  27 + var editors_initialised = this.editors_initialised(), self = this, editor;
  28 + if (!editors_initialised && refreshes) {
  29 + setTimeout(function() {
  30 + self.initialise_toggles(refreshes - 1);
  31 + }, 100);
  32 + return;
  33 + }
  34 +
  35 + // Create the toggle template for use later
  36 + this.toggleNodeTemplate = Y.Node.create('<a class="toggle_editor_toolbar" />');
  37 + this.toggleNodeTemplate.setContent(M.util.get_string('showeditortoolbar', 'form'));
  38 +
  39 + // Delegate clicks of the toggle_editor_toolbar
  40 + Y.one('body').delegate('click', this.toggle_collapse_from_event, 'a.toggle_editor_toolbar', this);
  41 +
  42 + // Set up editors which have already been created
  43 + for (editor in tinyMCE.editors) {
  44 + this.setup_collapse(tinyMCE.editors[editor]);
  45 + }
  46 +
  47 + // Set up for future editors.
  48 + // I haven't yet found a way of directly delegating the editor.onInit event. Instead we have to listen for the
  49 + // tinyMCE.onAddEditor event, and then add a further event listener to the editor's onInit event.
  50 + // onAddEditor is triggered before the editor has been created.
  51 + // We use Y.Bind to ensure that context is maintained.
  52 + tinyMCE.onAddEditor.add(Y.bind(this.add_setup_collapse_listener, this));
  53 +
  54 + },
  55 +
  56 + /**
  57 + * Setup a listener for a new editor which will actually set the editor up
  58 + * @param {Manager} mgr
  59 + * @param {Editor} ed
  60 + */
  61 + add_setup_collapse_listener : function (mgr, ed) {
  62 + // Bind the editor.onInit function to set this editor up. This ensures we maintain our context (this)
  63 + ed.onInit.add(Y.bind(this.setup_collapse, this));
  64 + },
  65 +
  66 + /**
  67 + * Setup the toggle system for the provided editor
  68 + *
  69 + * @param {Editor} ed The TinyMCE editor instance
  70 + */
  71 + setup_collapse : function(ed) {
  72 + var textarea = Y.Node(ed.getElement()),
  73 + editortable = Y.Node(ed.getContainer()).one('> table'),
  74 + thisToggleNode;
  75 +
  76 + // Does this text area support collapsing at all?
  77 + if (!textarea.hasClass('collapsible')) {
  78 + return;
  79 + }
  80 +
  81 + // Did we find an appropriate table to work with
  82 + if (!editortable) {
  83 + return;
  84 + }
  85 +
  86 + // Add toggle button.
  87 + thisToggleNode = this.toggleNodeTemplate.cloneNode(true);
  88 + editortable.get('parentNode').insert(thisToggleNode, editortable);
  89 +
  90 + // Toggle the toolbars initially.
  91 + if (Y.Node(ed.getElement()).hasClass('collapsed')) {
  92 + this.toggle_collapse(thisToggleNode, editortable, 0);
  93 + } else {
  94 + this.toggle_collapse(thisToggleNode, editortable, 1);
  95 + }
  96 + },
  97 +
  98 + /**
  99 + * Toggle the specified editor toolbars.
  100 + *
  101 + * @param {Node} button The toggle button which we have to change the text for
  102 + * @param {Node} editortable The table which the tinyMCE editor is in
  103 + * @param {Boolean} newstate The intended toggle state
  104 + */
  105 + toggle_collapse : function(button, editortable, newstate) {
  106 + var toolbar = editortable.one('td.mceToolbar').ancestor('tr'),
  107 + statusbar = editortable.one('.mceStatusbar').ancestor('tr'),
  108 + editor, iframe, size;
  109 +
  110 + // Check whether we have a state already.
  111 + if (typeof newstate === 'undefined') {
  112 + if (toolbar.getStyle('display') === 'none') {
  113 + newstate = 1;
  114 + } else {
  115 + newstate = 0;
  116 + }
  117 + }
  118 +
  119 + // Toggle the various states and update the button text to suit
  120 + if (newstate === 0) {
  121 + toolbar.hide();
  122 + statusbar.hide();
  123 + button.setContent(M.util.get_string('showeditortoolbar', 'form'));
  124 + } else {
  125 + toolbar.show();
  126 + statusbar.show();
  127 + button.setContent(M.util.get_string('hideeditortoolbar', 'form'));
  128 + }
  129 +
  130 + // TinyMCE renders the toolbar and path bar as part of the textarea. So toggling these items
  131 + // changes the required size of the rendered textarea. Frustrating but it's the way it's built.
  132 + // So we get TinyMCE to resize itself for us. Clunky but it works.
  133 +
  134 + // Get the tinyMCE editor object for this text area.
  135 + editorid = editortable.ancestor('div').one('textarea').get('id');
  136 + editor = tinyMCE.getInstanceById(editorid);
  137 +
  138 + // Somehow, this editor did not exist.
  139 + if (!editor) {
  140 + return;
  141 + }
  142 +
  143 + // Resize editor to reflect presence of toolbar and path bar..
  144 + iframe = editor.getBody();
  145 + if (iframe) {
  146 + size = tinymce.DOM.getSize(iframe);
  147 + // If objects exist resize editor.
  148 + if (size) {
  149 + editor.theme.resizeTo(size.w, size.h);
  150 + }
  151 + }
  152 + },
  153 +
  154 + toggle_collapse_from_event : function(thisevent) {
  155 + var button = thisevent.target.ancestor('a', true),
  156 + editortable = thisevent.target.ancestor('span', true).one('table.mceLayout');
  157 + this.toggle_collapse(button, editortable);
  158 + }
  159 + });
  160 +
  161 + M.editor_collapse = M.editor_collapse || {};
  162 + M.editor_collapse.init = function(params) {
  163 + return new COLLAPSE(params);
  164 + };
  165 +
  166 +}, '@VERSION@', {requires:['base', 'node', 'dom']});
15 lib/form/editor.php
@@ -53,7 +53,7 @@ class MoodleQuickForm_editor extends HTML_QuickForm_element {
53 53 /** @var array options provided to initalize filepicker */
54 54 protected $_options = array('subdirs' => 0, 'maxbytes' => 0, 'maxfiles' => 0, 'changeformat' => 0,
55 55 'areamaxbytes' => FILE_AREA_MAX_BYTES_UNLIMITED, 'context' => null, 'noclean' => 0, 'trusttext' => 0,
56   - 'return_types' => 7);
  56 + 'return_types' => 7, 'collapsible'=>0, 'collapsed' => 0);
57 57 // $_options['return_types'] = FILE_INTERNAL | FILE_EXTERNAL | FILE_REFERENCE
58 58
59 59 /** @var array values for editor */
@@ -383,7 +383,17 @@ function toHtml() {
383 383 if (!is_null($this->getAttribute('onblur')) && !is_null($this->getAttribute('onchange'))) {
384 384 $editorrules = ' onblur="'.htmlspecialchars($this->getAttribute('onblur')).'" onchange="'.htmlspecialchars($this->getAttribute('onchange')).'"';
385 385 }
386   - $str .= '<div><textarea id="'.$id.'" name="'.$elname.'[text]" rows="'.$rows.'" cols="'.$cols.'"'.$editorrules.'>';
  386 + $str .= '<div><textarea id="'.$id.'" name="'.$elname.'[text]" rows="'.$rows.'" cols="'.$cols.'"';
  387 + $classes = array();
  388 + if (isset($this->_options['collapsed']) && $this->_options['collapsed']) {
  389 + $this->_options['collapsible'] = 1;
  390 + $classes[] = 'collapsed';
  391 + }
  392 + if (isset($this->_options['collapsible']) && $this->_options['collapsible']) {
  393 + $classes[] = 'collapsible';
  394 + }
  395 + $str .= ' class="' . implode(' ', $classes) . '"';
  396 + $str .= $editorrules.'>';
387 397 $str .= s($text);
388 398 $str .= '</textarea></div>';
389 399
@@ -439,4 +449,5 @@ function getFrozenHtml() {
439 449
440 450 return '';
441 451 }
  452 +
442 453 }
10 question/type/edit_question_form.php
@@ -104,7 +104,7 @@ public function __construct($submiturl, $question, $category, $contexts, $formed
104 104 $this->context = context::instance_by_id($record->contextid);
105 105
106 106 $this->editoroptions = array('subdirs' => 1, 'maxfiles' => EDITOR_UNLIMITED_FILES,
107   - 'context' => $this->context);
  107 + 'context' => $this->context, 'collapsed' => 1);
108 108 $this->fileoptions = array('subdirs' => 1, 'maxfiles' => -1, 'maxbytes' => -1);
109 109
110 110 $this->category = $category;
@@ -186,7 +186,7 @@ protected function definition() {
186 186 $mform->addRule('name', null, 'required', null, 'client');
187 187
188 188 $mform->addElement('editor', 'questiontext', get_string('questiontext', 'question'),
189   - array('rows' => 15), $this->editoroptions);
  189 + array('rows' => 15), $this->get_non_collabsible_editor_options());
190 190 $mform->setType('questiontext', PARAM_RAW);
191 191
192 192 $mform->addElement('text', 'defaultmark', get_string('defaultmark', 'question'),
@@ -196,7 +196,7 @@ protected function definition() {
196 196 $mform->addRule('defaultmark', null, 'required', null, 'client');
197 197
198 198 $mform->addElement('editor', 'generalfeedback', get_string('generalfeedback', 'question'),
199   - array('rows' => 10), $this->editoroptions);
  199 + array('rows' => 10), $this->get_non_collabsible_editor_options());
200 200 $mform->setType('generalfeedback', PARAM_RAW);
201 201 $mform->addHelpButton('generalfeedback', 'generalfeedback', 'question');
202 202
@@ -673,4 +673,8 @@ public function validation($fromform, $files) {
673 673 * in the question type class.
674 674 */
675 675 public abstract function qtype();
  676 +
  677 + protected function get_non_collabsible_editor_options() {
  678 + return array_merge($this->editoroptions, array('collapsed' => 0));
  679 + }
676 680 }

0 comments on commit 2a22be6

Please sign in to comment.
Something went wrong with that request. Please try again.