Moodle 使用 Codemirror

  1. 在任何您要設定編輯區塊,加入以下 html 程式碼,即可使用 CodeMirror。其中變數 $inputcode 為輸入的程式碼,變數 $mode 可以指定程式語言,適用的語言非常多。例如 Python, Perl, C/C++, PHP, Ruby, Shell, Java。tabMode: 'shift' 讓內縮使用 TAB。
    <script> 
    var editor = CodeMirror.fromTextArea(document.getElementById("$inputcode"), { 
    	mode: $mode,  
    	indentUnit: 4, 
    	indentWithTabs: true, 
    	enterMode: 'flat', 
    	tabMode: 'shift',
    	lineNumbers: true, 
    	matchBrackets: true 
    })
    </script>
    
  2. 建立新的 codetextarea.php,準備 moodle 呼叫相關函式,使用 codetextarea。自由軟體的好處,在於開放原始碼,使用者可以在既有基礎上,增加修改程式。所以可以先從類似的程式 textarea.php 複製過來。
    [root@dywang moodle23]# cp lib/form/textarea.php lib/form/codetextarea.php
    
  3. 修改版權宣告及函式名。
    [root@dywang moodle23]# diff -urN -wbBE lib/form/textarea.php lib/form/codetextarea.php 
    --- lib/form/textarea.php	2012-06-26 01:14:43.000000000 +0800
    +++ lib/form/codetextarea.php	2014-03-02 14:20:04.566476633 +0800
    @@ -16,28 +16,28 @@
     
     /**
    - * Textarea type form element
    + * CodeTextarea type form element
      *
    - * Contains HTML class for a textarea type element
    + * Contains HTML class for a codetextarea type element
      *
      * @package   core_form
    - * @copyright 2006 Jamie Pratt <me@jamiep.org>
    + * @copyright 2013 De-Yu Wang <dywang@csie.cyut.edu.tw>
      * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      */
     
     require_once('HTML/QuickForm/textarea.php');
     
     /**
    - * Textarea type form element
    + * CodeTextarea type form element
      *
    - * HTML class for a textarea type element
    + * HTML class for a codetextarea type element
      *
      * @package   core_form
      * @category  form
    - * @copyright 2006 Jamie Pratt <me@jamiep.org>
    + * @copyright 2013 De-Yu Wang <dywang@csie.cyut.edu.tw>
      * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
      */
    -class MoodleQuickForm_textarea extends HTML_QuickForm_textarea{
    +class MoodleQuickForm_codetextarea extends HTML_QuickForm_textarea{
         /** @var string Need to store id of form as we may need it for helpbutton */
         var $_formid = ”;
    
  4. MoodleQuickForm_codetextarea 函式,若沒有指定程式語言,會以輸入的字串自動判斷程式語言,目前共有八種程式語言。
    @@ -54,7 +54,7 @@
          * @param string $elementLabel (optional) text field label
          * @param string $attributes (optional) Either a typical HTML attribute string or an associative array
          */
    -    function MoodleQuickForm_textarea($elementName=null, $elementLabel=null, $attributes=null) {
    +    function MoodleQuickForm_codetextarea($elementName=null, $elementLabel=null, $attributes=null) {
             parent::HTML_QuickForm_textarea($elementName, $elementLabel, $attributes);
         }
     
    @@ -100,7 +100,61 @@
                 return '<label class="accesshide" for="' . $this->getAttribute('id') . '" >' .
                         $this->getLabel() . '</label>' . parent::toHtml();
             } else {
    -            return parent::toHtml();
    +            if ($this->_flagFrozen) {
    +                return $this->getFrozenHtml();
    +            } else {
    +				if ( preg_match('/^#!\/usr\/bin\/python/',$this->_value) > 0 ) {
    +					$js='python/python'; 
    +					$mode='python'; 
    +				}
    +				elseif ( preg_match('/^#!\/usr\/bin\/php/',$this->_value) > 0 ) {
    +					$js='php/php'; 
    +					$mode='text/x-php'; 
    +				}
    +				elseif ( preg_match('/^#!\/bin\/b?a?sh/',$this->_value) > 0 ) {
    +					$js='shell/shell'; 
    +					$mode='shell'; 
    +				}
    +				elseif ( preg_match('/^#!\/usr\/bin\/perl/',$this->_value) > 0 ) {
    +					$js='perl/perl'; 
    +					$mode='perl'; 
    +				}
    +				elseif ( preg_match('/^#!\/usr\/bin\/ruby/',$this->_value) > 0 ) {
    +					$js='ruby/ruby'; 
    +					$mode='ruby'; 
    +				}
    +				elseif ( preg_match('/#include.*iostream/',$this->_value) > 0 ) { //for c++
    +					$js='clike/clike'; 
    +					$mode='text/x-c++src'; 
    +				}
    +				elseif ( preg_match('/#include.*stdio\.h/',$this->_value) > 0 ) { //for c
    +					$js='clike/clike'; 
    +					$mode='text/x-csrc'; 
    +				}
    +				elseif ( preg_match('/public\ *class/',$this->_value) > 0 ) { //for java
    +					$js='clike/clike'; 
    +					$mode='text/x-java'; 
    +				}
    +				else {
    +					$js = 'clike/clike';
    +					$mode = 'text/x-csrc';
    +				}
    +				$codemirror= '../lib/form/codemirror-3.19/';
    +				$src = '<link rel=stylesheet href=' . $codemirror . 'lib/codemirror.css>';
    +				$src .= '<script src=' . $codemirror . 'lib/codemirror.js></script>';
    +				$src .= '<script src=' . $codemirror . 'addon/edit/matchbrackets.js></script>';
    +				$src .= '<script src=' . $codemirror . 'mode/'. $js . '.js></script>';
    +				if ($js == "php/php") {$src .= '<script src=' . $codemirror . 'mode/clike/clike.js></script>';}
    +				//auto tab for enter newline
    +				$a=', indentUnit: 4, indentWithTabs: true, enterMode: \'flat\', tabMode: \'shift\'';
    +				$script = '<script>  var editor = CodeMirror.fromTextArea(document.getElementById(\'' . $this->_attributes[id] .'\'), {';
    +				$script .= ' mode: \'' . $mode . '\''. $a . ', lineNumbers: true, matchBrackets: true });</script>';
    +                return $this->_getTabs() . $src .
    +                       '<textarea' . $this->_getAttrString($this->_attributes) . '>' .
    +                       // because we wrap the form later we don't want the text indented
    +                       preg_replace("/(\r\n|\n|\r)/", '&#010;', htmlspecialchars($this->_value)) .
    +                       '</textarea>' . $script;
    +            }
             }
         }
    
  5. formslib.php 中加入新增的 codetextarea 函式的宣告。
    [root@dywang moodle23]# diff -urNwbBE ../moodle/lib/formslib.php lib/formslib.php
    --- ../moodle/lib/formslib.php	2012-08-10 08:05:01.000000000 +0800
    +++ lib/formslib.php	2013-11-18 08:47:36.906293437 +0800
    @@ -2615,6 +2615,7 @@
     MoodleQuickForm::registerElementType('tags', "$CFG->libdir/form/tags.php", 'MoodleQuickForm_tags');
     MoodleQuickForm::registerElementType('text', "$CFG->libdir/form/text.php", 'MoodleQuickForm_text');
     MoodleQuickForm::registerElementType('textarea', "$CFG->libdir/form/textarea.php", 'MoodleQuickForm_textarea');
    +MoodleQuickForm::registerElementType('codetextarea', "$CFG->libdir/form/codetextarea.php", 'MoodleQuickForm_codetextarea');
     MoodleQuickForm::registerElementType('url', "$CFG->libdir/form/url.php", 'MoodleQuickForm_url');
     MoodleQuickForm::registerElementType('warning', "$CFG->libdir/form/warning.php", 'MoodleQuickForm_warning');
    
  6. edit_script_form.php 中使用 codetextarea。
    [root@dywang script]# pwd
    /var/www/html/moodle23/question/type/script
    [root@dywang script]# vim edit_script_form.php
    ..............
        public function get_per_answer_fields($mform, $label, $gradeoptions,
                &$repeatedoptions, &$answersoption) {
            $repeated = array();
            $repeated[] = $mform->createElement('header', 'answerhdr', $label);
            $repeated[] = $mform->createElement('codetextarea', 'answer',
                    get_string('answer', 'question'), array('size' => 70,'cols'=>70, 'rows' => 20));
            $repeated[] = $mform->createElement('select', 'fraction',
                    get_string('grade'), $gradeoptions);
            $repeated[] = $mform->createElement('editor', 'feedback',
                    get_string('feedback', 'question'), array('rows' => 2), $this->editoroptions); //dywang
            $repeatedoptions['answer']['type'] = PARAM_RAW;
            $repeatedoptions['fraction']['default'] = 1; //dywang
            $answersoption = 'answers';
            return $repeated;
        }
    
  7. 解答實際結果畫面– python 程式。
    Image pythoncodea
  8. 學生作答實際結果畫面– python 程式。
    Image pythoncode
  9. 解答實際結果畫面– C 語言程式。
    Image ccodea
  10. 學生作答實際結果畫面– C 語言程式。
    Image ccode