]> git.mjollnir.org Git - moodle.git/commitdiff
various formslib work including bug fixes for MDL-8039 id attribute collision between...
authorjamiesensei <jamiesensei>
Sun, 7 Jan 2007 12:46:47 +0000 (12:46 +0000)
committerjamiesensei <jamiesensei>
Sun, 7 Jan 2007 12:46:47 +0000 (12:46 +0000)
20 files changed:
course/import/groups/import_form.php
lang/en_utf8/qtype_match.php [new file with mode: 0644]
lang/en_utf8/qtype_multichoice.php
lang/en_utf8/qtype_shortanswer.php [new file with mode: 0644]
lib/form/editorhelp.php
lib/formslib.php
lib/javascript-static.js
lib/questionlib.php
mod/choice/mod_form.php
mod/quiz/mod_form.php
question/question2.php
question/type/calculated/edit_calculated_form.php [new file with mode: 0644]
question/type/description/edit_description_form.php [new file with mode: 0644]
question/type/edit_question_form.php
question/type/essay/edit_essay_form.php [new file with mode: 0644]
question/type/match/edit_match_form.php [new file with mode: 0644]
question/type/multianswer/edit_multianswer_form.php [new file with mode: 0644]
question/type/multichoice/edit_multichoice_form.php [new file with mode: 0644]
question/type/questiontype.php
question/type/shortanswer/edit_shortanswer_form.php [new file with mode: 0644]

index 10c1b07a4196cceceae4da26856ddb882c106161..8391f7fd2e15510d1feb85b606485dc425c9c4da 100755 (executable)
@@ -12,7 +12,7 @@ class course_import_groups_form extends moodleform {
                $strimportgroups = get_string("importgroups");
 
         $this->set_upload_manager(new upload_manager('userfile', true, false, '', false, $maxuploadsize, true, true));
-        $this->set_max_file_size('', $maxuploadsize);
+        //$this->set_max_file_size('', $maxuploadsize);
 
         $mform->addElement('header', 'general', '');//fill in the data depending on page params
                                                     //later using set_defaults
diff --git a/lang/en_utf8/qtype_match.php b/lang/en_utf8/qtype_match.php
new file mode 100644 (file)
index 0000000..203cb0f
--- /dev/null
@@ -0,0 +1,5 @@
+<?php
+$string['addmoreqblanks'] = '{no} More Sets of Blanks';
+$string['notenoughquestions'] = 'You must supply at least $a question and answer pairs.';
+$string['nomatchinganswerforq'] = 'You must specify an answer for this question.';
+?>
\ No newline at end of file
index ab23104a5e3ee03c1e7d83a0f4586b77737207fb..7b04cd2a1b440dad0cf7b05af033637216a4c01e 100644 (file)
@@ -1,22 +1,27 @@
-<?PHP // $Id$ 
+<?PHP // $Id$
       // qtype_multichoice.php - created with Moodle 1.7 beta + (2006101003)
 
 
+$string['addmorechoiceblanks'] = 'Blanks for {no} More Choices';
 $string['answerhowmany'] = 'One or multiple answers?';
 $string['answersingleno'] = 'Multiple answers allowed';
 $string['answersingleyes'] = 'One answer only';
 $string['choiceno'] = 'Choice $a';
 $string['choices'] = 'Available choices';
 $string['clozeaid'] = 'Enter missing word';
+$string['correctfeedback'] = 'For any correct answer';
 $string['editingmultichoice'] = 'Editing a Multiple Choice question';
 $string['feedback'] = 'Feedback';
 $string['fillouttwochoices'] = 'You must fill out at least two choices.  Choices left blank will not be used.';
 $string['fractionsaddwrong'] = 'The positive grades you have chosen do not add up to 100%%<br />Instead, they add up to $a%%<br />Do you want to go back and fix this question?';
 $string['fractionsnomax'] = 'One of the answers should be 100%%, so that it is<br />possible to get a full grade for this question.<br />Do you want to go back and fix this question?';
+$string['incorrectfeedback'] = 'For any incorrect answer';
 $string['notenoughanswers'] = 'This type of question requires at least $a answers';
+$string['overallfeedback'] = 'Overall Feedback';
 $string['overallcorrectfeedback'] = 'Feedback for any correct answer';
 $string['overallincorrectfeedback'] = 'Feedback for any incorrect answer';
 $string['overallpartiallycorrectfeedback'] = 'Feedback for any partially correct answer';
+$string['partiallycorrectfeedback'] = 'For any partially correct answer';
 $string['shuffleanswers'] = 'Shuffle answers';
 $string['singleanswer'] = 'Choose one answer.';
 
diff --git a/lang/en_utf8/qtype_shortanswer.php b/lang/en_utf8/qtype_shortanswer.php
new file mode 100644 (file)
index 0000000..f79f8cd
--- /dev/null
@@ -0,0 +1,5 @@
+<?php
+$string['addmoreanswerblanks'] = 'Blanks for {no} More Answers';
+$string['answerno'] = 'Answer $a';
+$string['filloutoneanswer'] = 'You must provide at least one possible answer. Answers left blank will not be used. \'*\' can be used as a wildcard to match any characters. The first matching answer will be used to determine the score and feedback.';
+?>
\ No newline at end of file
index 1f82f57652df8acf1062a8b50aa56344bbb3b77b..2a43afa1723b2699a866b5b25c46625300b4e58c 100644 (file)
@@ -35,7 +35,7 @@ for ($i=1; ; $i++){
         $title = optional_param("title$i", '', PARAM_NOTAGS);
         $module = optional_param("module$i", 'moodle', PARAM_ALPHAEXT);
         $func[$i] = 'helpbutton';
-        $topics[$i] = array($keyword, $title, $module);
+        $topics[$i] = helplink($keyword, $title, $module);
     }
 
 }
index 09962abd54b1b1ce964e4988f7380ad2d1e64fab..fe6b1e8a12ec532a3fd25fb1207d4c7203b3363a 100644 (file)
@@ -446,11 +446,15 @@ class moodleform {
      * @param string $repeathiddenname name for hidden element storing no of repeats in this form
      * @param string $addfieldsname name for button to add more fields
      * @param int $addfieldsno how many fields to add at a time
-     * @param array $addstring array of params for get_string for name of button, $a is no of fields that
-     *                                  will be added.
+     * @param string $addstring name of button, {no} is replaced by no of blanks that will be added.
      * @return int no of repeats of element in this page
      */
-    function repeat_elements($elementobjs, $repeats, $options, $repeathiddenname, $addfieldsname, $addfieldsno=5, $addstring=array('addfields', 'form')){
+    function repeat_elements($elementobjs, $repeats, $options, $repeathiddenname, $addfieldsname, $addfieldsno=5, $addstring=null){
+        if ($addstring===null){
+            $addstring = get_string('addfields', 'form', $addfieldsno);
+        } else {
+            $addstring = str_ireplace('{no}', $addfieldsno, $addstring);
+        }
         $repeats = optional_param($repeathiddenname, $repeats, PARAM_INT);
         $addfields = optional_param($addfieldsname, '', PARAM_TEXT);
         if (!empty($addfields)){
@@ -463,12 +467,16 @@ class moodleform {
         $mform->setConstants(array($repeathiddenname=>$repeats));
         for ($i=0; $i<$repeats; $i++) {
             foreach ($elementobjs as $elementobj){
-                $elementclone=clone($elementobj);
+                $elementclone = clone($elementobj);
                 $name=$elementclone->getName();
                 $elementclone->setName($name."[$i]");
                 if (is_a($elementclone, 'HTML_QuickForm_header')){
                     $value=$elementclone->_text;
-                    $elementclone->setValue($value.' '.($i+1));
+                    $elementclone->setValue(str_replace('{no}', ($i+1), $value));
+
+                } else {
+                    $value=$elementclone->getLabel();
+                    $elementclone->setLabel(str_replace('{no}', ($i+1), $value));
 
                 }
                 $mform->addElement($elementclone);
@@ -503,7 +511,7 @@ class moodleform {
                 }
             }
         }
-        $mform->addElement('submit', $addfieldsname, get_string('addfields', 'form', $addfieldsno));
+        $mform->addElement('submit', $addfieldsname, $addstring);
 
         $mform->closeHeaderBefore($addfieldsname);
 
@@ -597,12 +605,14 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
      */
     function MoodleQuickForm($formName, $method, $action, $target='', $attributes=null){
         global $CFG;
+        static $formcounter = 1;
 
         HTML_Common::HTML_Common($attributes);
         $target = empty($target) ? array() : array('target' => $target);
         $this->_formName = $formName;
         //no 'name' atttribute for form in xhtml strict :
-        $attributes = array('action'=>$action, 'method'=>$method, 'id'=>strtr($formName, '_', '-')) + $target;
+        $attributes = array('action'=>$action, 'method'=>$method, 'id'=>'mform'.$formcounter) + $target;
+        $formcounter++;
         $this->updateAttributes($attributes);
 
         //this is custom stuff for Moodle :
@@ -1127,7 +1137,7 @@ function validate_' . $this->_formName . '(frm) {
     function getLockOptionEndScript(){
         $js = '<script type="text/javascript">'."\n";
         $js .= '//<![CDATA['."\n";
-        $js .= "var ".$this->_formName."items= {";
+        $js .= "var ".$this->getAttribute('id')."items= {";
         foreach ($this->_dependencies as $dependentOn => $elements){
             $js .= "'$dependentOn'".' : {dependents :[';
             foreach ($elements as $element){
index f015ea8386b947d47f7afaaa595113763dcb4556..9af0df8a255f7a6eb9642136772538cee7c14f22 100644 (file)
@@ -83,8 +83,7 @@ function unlockoption(form,item) {
 }
 function lockoptionsall(formid) {
   var lock = new Object();
-  var varname = formid.replace(/\-/g, '_');
-  var items = eval(varname+'items');
+  var items = eval(formid+'items');
   var form = document.forms[formid];
   for (var master in items){
       var subitems=items[master].dependents;
index 03ab0234d14f1fe660965803ac1772fa60f70ced..f091633a96663c54bfcd09c454a9e4dd49aea687 100644 (file)
@@ -59,6 +59,20 @@ define("ESSAY",         "essay");
  */
 define("QUESTION_NUMANS", "10");
 
+/**
+ * Constant determines the number of answer boxes supplied in the editing
+ * form for multiple choice and similar question types to start with, with
+ * the option of adding QUESTION_NUMANS_ADD more answers.
+ */
+define("QUESTION_NUMANS_START", 3);
+
+/**
+ * Constant determines the number of answer boxes to add in the editing
+ * form for multiple choice and similar question types when the user presses
+ * 'add form fields button'.
+ */
+define("QUESTION_NUMANS_ADD", 3);
+
 /**
  * The options used when popping up a question preview window in Javascript.
  */
@@ -97,7 +111,7 @@ $QTYPE_MENU = array();
  * String in the format "'type1','type2'" that can be used in SQL clauses like
  * "WHERE q.type IN ($QTYPE_MANUAL)".
  */
-$QTYPE_MANUAL = ''; 
+$QTYPE_MANUAL = '';
 /**
  * String in the format "'type1','type2'" that can be used in SQL clauses like
  * "WHERE q.type NOT IN ($QTYPE_EXCLUDE_FROM_RANDOM)".
@@ -106,12 +120,12 @@ $QTYPE_EXCLUDE_FROM_RANDOM = '';
 
 /**
  * Add a new question type to the various global arrays above.
- * 
+ *
  * @param object $qtype An instance of the new question type class.
  */
 function question_register_questiontype($qtype) {
     global $QTYPES, $QTYPE_MENU, $QTYPE_MANUAL, $QTYPE_EXCLUDE_FROM_RANDOM;
-    
+
     $name = $qtype->name();
     $QTYPES[$name] = $qtype;
     $menuname = $qtype->menu_name();
@@ -135,7 +149,7 @@ function question_register_questiontype($qtype) {
 require_once("$CFG->dirroot/question/type/questiontype.php");
 
 // Load the questiontype.php file for each question type
-// These files in turn call question_register_questiontype() 
+// These files in turn call question_register_questiontype()
 // with a new instance of each qtype class.
 $qtypenames= get_list_of_plugins('question/type');
 foreach($qtypenames as $qtypename) {
@@ -226,7 +240,7 @@ function question_list_instances($questionid) {
 }
 
 
-/** 
+/**
  * Returns list of 'allowed' grades for grade selection
  * formatted suitably for dropdown box function
  * @return object ->gradeoptionsfull full array ->gradeoptions +ve only
@@ -315,14 +329,14 @@ function match_grade_options($gradeoptionsfull, $grade, $matchgrades='error') {
     }
     else {
         return false;
-    } 
+    }
 }
 
 /**
  * Tests whether a category is in use by any activity module
  *
  * @return boolean
- * @param integer $categoryid 
+ * @param integer $categoryid
  * @param boolean $recursive Whether to examine category children recursively
  */
 function question_category_isused($categoryid, $recursive = false) {
@@ -383,7 +397,7 @@ function delete_attempt($attemptid) {
  */
 function delete_question($questionid) {
     global $QTYPES;
-    
+
     // Do not delete a question if it is used by an activity module
     if (count(question_list_instances($questionid))) {
         return;
@@ -400,7 +414,7 @@ function delete_question($questionid) {
 
     if ($states = get_records('question_states', 'question', $questionid)) {
         $stateslist = implode(',', array_keys($states));
-    
+
         // delete questiontype-specific data
         foreach ($QTYPES as $qtype) {
             $qtype->delete_states($stateslist);
@@ -421,7 +435,7 @@ function delete_question($questionid) {
             }
         }
     }
-    
+
     // Finally delete the question record itself
     delete_records('question', 'id', $questionid);
 
@@ -543,9 +557,9 @@ function question_delete_course($course, $feedback=true) {
 
 /**
  * Private function to factor common code out of get_question_options().
- * 
+ *
  * @param object $question the question to tidy.
- * @return boolean true if successful, else false. 
+ * @return boolean true if successful, else false.
  */
 function _tidy_question(&$question) {
     global $QTYPES;
@@ -563,7 +577,7 @@ function _tidy_question(&$question) {
  *
  * Can be called either with an array of question objects or with a single
  * question object.
- * 
+ *
  * @param mixed $questions Either an array of question objects to be updated
  *         or just a single question object
  * @return bool Indicates success or failure.
@@ -843,7 +857,7 @@ function question_extract_responses($questions, $formdata, $defaultevent=QUESTIO
 
             // Update the state with the new response
             $actions[$quid]->responses[$key] = $response;
-            
+
             // Set the timestamp
             $actions[$quid]->timestamp = $time;
         }
@@ -941,7 +955,7 @@ function regrade_question_in_attempt($question, $attempt, $cmoptions, $verbose=f
         $states = array_values($states);
 
         // Subtract the grade for the latest state from $attempt->sumgrades to get the
-        // sumgrades for the attempt without this question. 
+        // sumgrades for the attempt without this question.
         $attempt->sumgrades -= $states[count($states)-1]->grade;
 
         // Initialise the replaystate
@@ -992,7 +1006,7 @@ function regrade_question_in_attempt($question, $attempt, $cmoptions, $verbose=f
             }
 
             $replaystate->id = $states[$j]->id;
-            $replaystate->changed = true; 
+            $replaystate->changed = true;
             $replaystate->update = true; // This will ensure that the existing database entry is updated rather than a new one created
             save_question_session($question, $replaystate);
         }
@@ -1047,10 +1061,10 @@ function question_process_responses(&$question, &$state, $action, $cmoptions, &$
     if (question_isgradingevent($action->event)) {
         $state->responses = $state->last_graded->responses;
     }
-    
+
     // Check for unchanged responses (exactly unchanged, not equivalent).
     // We also have to catch questions that the student has not yet attempted
-    $sameresponses = !$state->last_graded->event == QUESTION_EVENTOPEN && 
+    $sameresponses = !$state->last_graded->event == QUESTION_EVENTOPEN &&
             $QTYPES[$question->qtype]->compare_responses($question, $action, $state);
 
     // If the response has not been changed then we do not have to process it again
@@ -1084,8 +1098,8 @@ function question_process_responses(&$question, &$state, $action, $cmoptions, &$
 
     } else { // grading event
 
-        // Unless the attempt is closing, we want to work out if the current responses 
-        // (or equivalent responses) were already given in the last graded attempt. 
+        // Unless the attempt is closing, we want to work out if the current responses
+        // (or equivalent responses) were already given in the last graded attempt.
         if(QUESTION_EVENTCLOSE != $action->event && QUESTION_EVENTOPEN != $state->last_graded->event &&
                 $QTYPES[$question->qtype]->compare_responses($question, $state, $state->last_graded)) {
             $state->event = QUESTION_EVENTDUPLICATE;
@@ -1454,12 +1468,12 @@ function sort_categories_by_tree(&$categories, $id = 0, $level = 1) {
 
 /**
  * Private method, only for the use of add_indented_names().
- * 
+ *
  * Recursively adds an indentedname field to each category, starting with the category
- * with id $id, and dealing with that category and all its children, and 
+ * with id $id, and dealing with that category and all its children, and
  * return a new array, with those categories in the right order.
  *
- * @param array $categories an array of categories which has had childids 
+ * @param array $categories an array of categories which has had childids
  *          fields added by flatten_category_tree(). Passed by reference for
  *          performance only. It is not modfied.
  * @param int $id the category to start the indenting process from.
@@ -1467,39 +1481,39 @@ function sort_categories_by_tree(&$categories, $id = 0, $level = 1) {
  * @return array a new array of categories, in the right order for the tree.
  */
 function flatten_category_tree(&$categories, $id, $depth = 0) {
-    
+
     // Indent the name of this category.
     $newcategories = array();
     $newcategories[$id] = $categories[$id];
     $newcategories[$id]->indentedname = str_repeat('&nbsp;&nbsp;&nbsp;', $depth) . $categories[$id]->name;
-    
+
     // Recursively indent the children.
     foreach ($categories[$id]->childids as $childid) {
         $newcategories = $newcategories + flatten_category_tree($categories, $childid, $depth + 1);
     }
-    
+
     // Remove the childids array that were temporarily added.
     unset($newcategories[$id]->childids);
-    
+
     return $newcategories;
 }
 
 /**
  * Format categories into an indented list reflecting the tree structure.
- * 
+ *
  * @param array $categories An array of category objects, for example from the.
  * @return array The formatted list of categories.
  */
 function add_indented_names($categories) {
 
-    // Add an array to each category to hold the child category ids. This array will be removed 
+    // Add an array to each category to hold the child category ids. This array will be removed
     // again by flatten_category_tree(). It should not be used outside these two functions.
     foreach (array_keys($categories) as $id) {
         $categories[$id]->childids = array();
     }
 
     // Build the tree structure, and record which categories are top-level.
-    // We have to be careful, because the categories array may include published 
+    // We have to be careful, because the categories array may include published
     // categories from other courses, but not their parents.
     $toplevelcategoryids = array();
     foreach (array_keys($categories) as $id) {
@@ -1521,9 +1535,9 @@ function add_indented_names($categories) {
 
 /**
  * Output a select menu of question categories.
- * 
+ *
  * Categories from this course and (optionally) published categories from other courses
- * are included. Optionally, only categories the current user may edit can be included. 
+ * are included. Optionally, only categories the current user may edit can be included.
  *
  * @param integer $courseid the id of the course to get the categories for.
  * @param integer $published if true, include publised categories from other courses.
@@ -1532,7 +1546,7 @@ function add_indented_names($categories) {
  */
 function question_category_select_menu($courseid, $published = false, $only_editable = false, $selected = "") {
     global $CFG;
-    
+
     // get sql fragment for published
     $publishsql="";
     if ($published) {
@@ -1540,7 +1554,7 @@ function question_category_select_menu($courseid, $published = false, $only_edit
     }
 
     $categories = get_records_sql("
-            SELECT cat.*, c.shortname AS coursename 
+            SELECT cat.*, c.shortname AS coursename
             FROM {$CFG->prefix}question_categories cat, {$CFG->prefix}course c
             WHERE c.id = cat.course AND (cat.course = $courseid $publishsql)
             ORDER BY cat.parent, cat.sortorder, cat.name ASC");
@@ -1612,7 +1626,7 @@ function create_category_path( $catpath, $delimiter='/', $courseid=0 ) {
             $parent = $category->id;
         }
         else {
-            // create the new category        
+            // create the new category
             $category = new object;
             $category->course = $courseid;
             $category->name = $catname;
@@ -1639,7 +1653,7 @@ function create_category_path( $catpath, $delimiter='/', $courseid=0 ) {
 /**
  * Get list of available import or export formats
  * @param string $type 'import' if import list, otherwise export list assumed
- * @return array sorted list of import/export formats available 
+ * @return array sorted list of import/export formats available
 **/
 function get_import_export_formats( $type ) {
 
index 1342ef750ded3324ba42d49b7d14de3dbe49aef9..b9b67f6e05cd67dd60f305eab5bcf8d0f29c2ddd 100644 (file)
@@ -24,7 +24,7 @@ class mod_choice_mod_form extends moodleform_mod {
 
 //-------------------------------------------------------------------------------
         $repeatarray=array();
-        $repeatarray[] = &MoodleQuickForm::createElement('header', '', get_string('choice','choice'));
+        $repeatarray[] = &MoodleQuickForm::createElement('header', '', get_string('choice','choice').' {no}');
         $repeatarray[] = &MoodleQuickForm::createElement('text', 'option', get_string('choice','choice'));
         $repeatarray[] = &MoodleQuickForm::createElement('text', 'limit', get_string('limit','choice'));
         $repeatarray[] = &MoodleQuickForm::createElement('hidden', 'optionid', 0);
index d0703b3ab178a57d915f149cba3323e95cd44f1b..7546d8b293da11e1d93ba03d8e99006532355b53 100644 (file)
@@ -205,7 +205,7 @@ class mod_quiz_mod_form extends moodleform_mod {
 //-------------------------------------------------------------------------------
                $this->standard_coursemodule_elements();
 //-------------------------------------------------------------------------------
-        $mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'quiz'));
+        $mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'quiz').' {no}');
                $mform->setHelpButton('overallfeedbackhdr', array('overallfeedback', get_string('overallfeedback', 'quiz'), 'quiz'));
 
                $mform->addElement('static', 'gradeboundarystatic1', get_string('gradeboundary', 'quiz'), '100%');
index 2e95e9158a0f35e7560a5a591c9c1f1f662ac9ce..ad70e3cf22a6b2c2bccd4bf7c341750539a5f8e7 100644 (file)
@@ -62,7 +62,7 @@ $coursecontext = get_context_instance(CONTEXT_COURSE, $category->course);
 require_capability('moodle/question:manage', $coursecontext);
 
 // Create the question editing form.
-$mform = $QTYPES[$question->qtype]->create_editing_form($submiturl);
+$mform = $QTYPES[$question->qtype]->create_editing_form($submiturl, $question, $category->course);
 if ($mform === null) {
     print_error('missingimportantcode', 'question', $returnurl, 'question editing form definition');
 }
@@ -76,12 +76,11 @@ if ($mform->is_cancelled()){
     }
     $question = $QTYPES[$qtype]->save_question($question, $data, $COURSE);
 
-    $strsaved = get_string('changessaved');
     if (optional_param('inpopup', 0, PARAM_BOOL)) {
-        notify($strsaved, '');
+        notify(get_string('changessaved'), '');
         close_window(3);
     } else {
-        redirect($SESSION->returnurl, $strsaved);
+        redirect($SESSION->returnurl);
     }
 } else {
     // Display the question editing form
@@ -95,6 +94,9 @@ if ($mform->is_cancelled()){
                 get_string("editquestions", "quiz").'</a> -> '.$streditingquestion;
     }
     print_header_simple($streditingquestion, '', $strediting);
+
+    print_heading_with_help(get_string("editing".$question->qtype, "quiz"), $question->qtype, "quiz");
+
     $mform->set_defaults($question);
     $mform->display();
     print_footer($COURSE);
diff --git a/question/type/calculated/edit_calculated_form.php b/question/type/calculated/edit_calculated_form.php
new file mode 100644 (file)
index 0000000..90291a0
--- /dev/null
@@ -0,0 +1,114 @@
+<?php
+/**
+ * Defines the editing form for the calculated question type.
+ *
+ * @copyright &copy; 2007 Jamie Pratt
+ * @author Jamie Pratt me@jamiep.org
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package questions
+ */
+
+/**
+ * calculated editing form definition.
+ */
+class question_edit_calculated_form extends question_edit_form {
+    /**
+     * Add question-type specific form fields.
+     *
+     * @param object $mform the form being built.
+     */
+    function definition_inner(&$mform) {
+        $mform->addElement('text', 'answers[0]', get_string("correctanswerformula", "quiz"));
+        $mform->setType('answers[0]', PARAM_NOTAGS);
+
+        $mform->addElement('hidden', 'fraction[0]', '1.0');
+
+        $mform->addElement('text', 'tolerance[0]', get_string("tolerance", "quiz"));
+        $mform->setType('tolerance[0]', PARAM_NOTAGS);
+
+        $mform->addElement('select', 'shuffleanswers', get_string('shuffleanswers', 'qtype_calculated') );
+        $mform->setHelpButton('shuffleanswers', array('calculatedshuffle', get_string('shuffleanswers','qtype_calculated'), 'quiz'));
+
+/*      $mform->addElement('static', 'answersinstruct', get_string('choices', 'qtype_calculated'), get_string('fillouttwochoices', 'qtype_calculated'));
+        $mform->closeHeaderBefore('answersinstruct');
+*/
+        $creategrades = get_grade_options();
+        $gradeoptions = $creategrades->gradeoptionsfull;
+        $repeated = array();
+        $repeated[] =& $mform->createElement('header', 'choicehdr', get_string('choiceno', 'qtype_calculated', '{no}'));
+        $repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'));
+        $repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
+        $repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'));
+
+        if (isset($this->question->options)){
+            $countanswers = count($this->question->options->answers);
+        } else {
+            $countanswers = 0;
+        }
+        $repeatsatstart = (QUESTION_NUMANS_START > ($countanswers + QUESTION_NUMANS_ADD))?
+                            QUESTION_NUMANS_START : ($countanswers + QUESTION_NUMANS_ADD);
+        $repeatedoptions = array();
+        $repeatedoptions['answer']['type'] = PARAM_TEXT;
+        $repeatedoptions['fraction']['default'] = 0;
+        $this->repeat_elements($repeated, $repeatsatstart, $repeatedoptions, 'noanswers', 'addanswers', QUESTION_NUMANS_ADD, get_string('addmorechoiceblanks', 'qtype_calculated'));
+
+        $mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_calculated'));
+
+        $mform->addElement('htmleditor', 'correctfeedback', get_string('correctfeedback', 'qtype_calculated'));
+        $mform->setType('correctfeedback', PARAM_RAW);
+
+        $mform->addElement('htmleditor', 'partiallycorrectfeedback', get_string('partiallycorrectfeedback', 'qtype_calculated'));
+        $mform->setType('partiallycorrectfeedback', PARAM_RAW);
+
+        $mform->addElement('htmleditor', 'incorrectfeedback', get_string('incorrectfeedback', 'qtype_calculated'));
+        $mform->setType('incorrectfeedback', PARAM_RAW);
+
+    }
+
+    function set_defaults($question) {
+        if (isset($question->options)){
+            $answers = $question->options->answers;
+            if (count($answers)) {
+                $key = 0;
+                foreach ($answers as $answer){
+                    $default_values['answer['.$key.']'] = $answer->answer;
+                    $default_values['fraction['.$key.']'] = $answer->fraction;
+                    $default_values['feedback['.$key.']'] = $answer->feedback;
+                    $key++;
+                }
+            }
+            $default_values['single'] =  $question->options->single;
+            $default_values['shuffleanswers'] =  $question->options->shuffleanswers;
+            $default_values['correctfeedback'] =  $question->options->correctfeedback;
+            $default_values['partiallycorrectfeedback'] =  $question->options->partiallycorrectfeedback;
+            $default_values['overallincorrectfeedback'] =  $question->options->overallincorrectfeedback;
+            $question = (object)((array)$question + $default_values);
+        }
+        parent::set_defaults($question);
+    }
+
+    function qtype() {
+        return 'calculated';
+    }
+
+    function validation($data){
+        $errors = array();
+        $answers = $data['answer'];
+        $answercount = 0;
+        foreach ($answers as $answer){
+            $trimmedanswer = trim($answer);
+            if (!empty($trimmedanswer)){
+                $answercount++;
+            }
+        }
+        if ($answercount==0){
+            $errors['answer[0]'] = get_string('notenoughanswers', 'qtype_calculated', 2);
+            $errors['answer[1]'] = get_string('notenoughanswers', 'qtype_calculated', 2);
+        } elseif ($answercount==1){
+            $errors['answer[1]'] = get_string('notenoughanswers', 'qtype_calculated', 2);
+
+        }
+        return $errors;
+    }
+}
+?>
\ No newline at end of file
diff --git a/question/type/description/edit_description_form.php b/question/type/description/edit_description_form.php
new file mode 100644 (file)
index 0000000..be11cd9
--- /dev/null
@@ -0,0 +1,35 @@
+<?php
+/**
+ * Defines the editing form for the description question type.
+ *
+ * @copyright &copy; 2007 Jamie Pratt
+ * @author Jamie Pratt me@jamiep.org
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package questions
+ */
+
+/**
+ * description editing form definition.
+ */
+class question_edit_description_form extends question_edit_form {
+    /**
+     * Add question-type specific form fields.
+     *
+     * @param MoodleQuickForm $mform the form being built.
+     */
+    function definition_inner(&$mform) {
+        //don't need these default elements :
+        $mform->removeElement('defaultgrade');
+        $mform->removeElement('penalty');
+
+        $mform->addElement('hidden', 'defaultgrade', 0);
+    }
+
+
+    function qtype() {
+        return 'description';
+    }
+
+
+}
+?>
\ No newline at end of file
index 2e130655e4e8bd64a7a7a018d1e8aa40f5aee9b1..dad8fb2be349fa98ed2408928e1fa286d0475a15 100644 (file)
  * method.
  */
 class question_edit_form extends moodleform {
+    /**
+     * Question object with options and answers already loaded by get_question_options
+     * Be careful how you use this it is needed sometimes to set up the structure of the
+     * form in definition_inner but data is always loaded into the form with set_defaults.
+     *
+     * @var object
+     */
+    var $question;
+    /**
+     * Course id
+     *
+     * @var integer
+     */
+    var $courseid;
+    function question_edit_form($submiturl, $question){
+        $this->question = $question;
+        parent::moodleform($submiturl);
+    }
     /**
      * Build the form definition.
      *
@@ -23,38 +41,42 @@ class question_edit_form extends moodleform {
      * override this method and remove the ones you don't want with $mform->removeElement().
      */
     function definition() {
-        global $COURSE;
+        global $COURSE, $CFG;
 
         $qtype = $this->qtype();
         $langfile = "qtype_$qtype";
 
         $mform =& $this->_form;
-        $renderer =& $mform->defaultRenderer();
 
         // Standard fields at the start of the form.
-        $mform->addElement('header', 'formheader', get_string("editing$qtype", $langfile));
-        $mform->setHelpButton('formheader', array($qtype, get_string($qtype, $qtype), $qtype));
+        $mform->addElement('header', 'generalheader', get_string("general", 'form'));
 
-        $mform->addElement('questioncategory', 'category', get_string('category', 'quiz'),
+        /*$mform->addElement('questioncategory', 'category', get_string('category', 'quiz'),
                 array('courseid' => $COURSE->id, 'published' => true, 'only_editable' => true));
-
+*/
         $mform->addElement('text', 'name', get_string('questionname', 'quiz'),
                 array('size' => 50));
-        $mform->setType('name', PARAM_MULTILANG);
+        $mform->setType('name', PARAM_TEXT);
         $mform->addRule('name', null, 'required', null, 'client');
 
         $mform->addElement('htmleditor', 'questiontext', get_string('questiontext', 'quiz'),
                 array('rows' => 15, 'course' => $COURSE->id));
         $mform->setType('questiontext', PARAM_RAW);
-        $mform->setHelpButton('questiontext', array('questiontext', get_string('questiontext', 'quiz'), 'quiz'));
+        $mform->setHelpButton('questiontext', array(array('questiontext', get_string('questiontext', 'quiz'), 'quiz'), 'richtext'), false, 'editorhelpbutton');
         $mform->addElement('format', 'questiontextformat', get_string('format'));
 
+        make_upload_directory("$COURSE->id");    // Just in case
+        $coursefiles = get_directory_list("$CFG->dataroot/$COURSE->id", $CFG->moddata);
+        foreach ($coursefiles as $filename) {
+            if (mimeinfo("icon", $filename) == "image.gif") {
+                $images["$filename"] = $filename;
+            }
+        }
         if (empty($images)) {
             $mform->addElement('static', 'image', get_string('imagedisplay', 'quiz'), get_string('noimagesyet'));
         } else {
             $images[''] = get_string('none');
             $mform->addElement('select', 'image', get_string('imagedisplay', 'quiz'), $images);
-            $mform->setType('image', PARAM_FILE);
         }
 
         $mform->addElement('text', 'defaultgrade', get_string('defaultgrade', 'quiz'),
@@ -89,15 +111,7 @@ class question_edit_form extends moodleform {
         $mform->addElement('hidden', 'versioning');
         $mform->setType('versioning', PARAM_BOOL);
 
-        $buttonarray = array();
-        $buttonarray[] = &$mform->createElement('submit', 'submitbutton', get_string('savechanges'));
-        if (!empty($id)) {
-            $buttonarray[] = &$mform->createElement('submit', 'makecopy', get_string('makecopy', 'quiz'));
-        }
-        $buttonarray[] = &$mform->createElement('reset', 'resetbutton', get_string('revert'));
-        $buttonarray[] = &$mform->createElement('cancel');
-        $mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
-        $renderer->addStopFieldsetElements('buttonar');
+        $this->add_action_buttons();
     }
 
     /**
@@ -111,7 +125,12 @@ class question_edit_form extends moodleform {
 
     function set_defaults($question) {
         global $QTYPES;
-        $QTYPES[$question->qtype]->set_default_options($question);
+        if (!isset($question->id)){
+            $QTYPES[$question->qtype]->set_default_options($question);
+        }
+        if (empty($question->image)){
+            unset($question->image);
+        }
         parent::set_defaults($question);
     }
 
diff --git a/question/type/essay/edit_essay_form.php b/question/type/essay/edit_essay_form.php
new file mode 100644 (file)
index 0000000..d99cb82
--- /dev/null
@@ -0,0 +1,40 @@
+<?php
+/**
+ * Defines the editing form for the essay question type.
+ *
+ * @copyright &copy; 2007 Jamie Pratt
+ * @author Jamie Pratt me@jamiep.org
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package questions
+ */
+
+/**
+ * essay editing form definition.
+ */
+class question_edit_essay_form extends question_edit_form {
+    /**
+     * Add question-type specific form fields.
+     *
+     * @param MoodleQuickForm $mform the form being built.
+     */
+    function definition_inner(&$mform) {
+        $mform->addElement('htmleditor', 'feedback', print_string("feedback", "quiz"));
+        $mform->setType('feedback', PARAM_RAW);
+
+        $mform->addElement('hidden', 'fraction', 0);
+    }
+
+    function set_defaults($question) {
+        if (isset($question->options)){
+            $question->feedback = $question->options->answer->feedback;
+        }
+        parent::set_defaults($question);
+    }
+
+    function qtype() {
+        return 'essay';
+    }
+
+
+}
+?>
\ No newline at end of file
diff --git a/question/type/match/edit_match_form.php b/question/type/match/edit_match_form.php
new file mode 100644 (file)
index 0000000..e36beef
--- /dev/null
@@ -0,0 +1,98 @@
+<?php
+/**
+ * Defines the editing form for the match question type.
+ *
+ * @copyright &copy; 2007 Jamie Pratt
+ * @author Jamie Pratt me@jamiep.org
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package questions
+ */
+
+/**
+ * match editing form definition.
+ */
+class question_edit_match_form extends question_edit_form {
+    /**
+     * Add question-type specific form fields.
+     *
+     * @param object $mform the form being built.
+     */
+    function definition_inner(&$mform) {
+        $mform->addElement('selectyesno', 'shuffleanswers', get_string('shuffle', 'quiz'));
+        $mform->setHelpButton('shuffleanswers', array('matchshuffle', get_string('shuffle','quiz'), 'quiz'));
+
+        $mform->addElement('static', 'answersinstruct', get_string('choices', 'quiz'), get_string('filloutthreequestions', 'quiz'));
+        $mform->closeHeaderBefore('answersinstruct');
+
+        $repeated = array();
+        $repeated[] =& $mform->createElement('header', 'choicehdr', get_string('questionno', 'quiz', '{no}'));
+        $repeated[] =& $mform->createElement('textarea', 'subquestions', get_string('question', 'quiz'), array('cols'=>40, 'rows'=>3));
+        $repeated[] =& $mform->createElement('text', 'subanswers', get_string('answer', 'quiz'), array('size'=>50));
+
+        if (isset($this->question->options)){
+            $countsubquestions = count($this->question->options->subquestions);
+        } else {
+            $countsubquestions = 0;
+        }
+        $repeatsatstart = (QUESTION_NUMANS_START > ($countsubquestions + QUESTION_NUMANS_ADD))?
+                            QUESTION_NUMANS_START : ($countsubquestions + QUESTION_NUMANS_ADD);
+        $repeatedoptions = array();
+        $repeatedoptions['subanswer']['type'] = PARAM_TEXT;
+        $repeatedoptions['subquestion']['type'] = PARAM_TEXT;
+
+        $this->repeat_elements($repeated, $repeatsatstart, $repeatedoptions, 'noanswers', 'addanswers', QUESTION_NUMANS_ADD, get_string('addmoreqblanks', 'qtype_match'));
+
+    }
+
+    function set_defaults($question) {
+        if (isset($question->options)){
+            $subquestions = $question->options->subquestions;
+            if (count($subquestions)) {
+                $key = 0;
+                foreach ($subquestions as $subquestion){
+                    $default_values['subanswers['.$key.']'] = $subquestion->answertext;
+                    $default_values['subquestions['.$key.']'] = $subquestion->questiontext;
+                    $key++;
+                }
+            }
+            $default_values['shuffleanswers'] =  $question->options->shuffleanswers;
+            $question = (object)((array)$question + $default_values);
+        }
+        parent::set_defaults($question);
+    }
+
+    function qtype() {
+        return 'match';
+    }
+
+    function validation($data){
+        $errors = array();
+        print_object($data);
+        $answers = $data['subanswers'];
+        $questions = $data['subquestions'];
+        $questioncount = 0;
+        foreach ($questions as $key => $question){
+            $trimmedquestion = trim($question);
+            $trimmedanswer = trim($answers[$key]);
+            if (!empty($trimmedanswer) && !empty($trimmedquestion)){
+                $questioncount++;
+            }
+            if (!empty($trimmedquestion) && empty($trimmedanswer)){
+                $errors['subanswers['.$key.']'] = get_string('nomatchinganswerforq', 'qtype_match', $trimmedquestion);
+            }
+        }
+        if ($questioncount==0){
+            $errors['subquestions[0]'] = get_string('notenoughquestions', 'qtype_match', 3);
+            $errors['subquestions[1]'] = get_string('notenoughquestions', 'qtype_match', 3);
+            $errors['subquestions[2]'] = get_string('notenoughquestions', 'qtype_match', 3);
+        } elseif ($questioncount==1){
+            $errors['subquestions[1]'] = get_string('notenoughquestions', 'qtype_match', 3);
+            $errors['subquestions[2]'] = get_string('notenoughquestions', 'qtype_match', 3);
+
+        } elseif ($questioncount==2){
+            $errors['subquestions[2]'] = get_string('notenoughquestions', 'qtype_match', 3);
+        }
+        return $errors;
+    }
+}
+?>
\ No newline at end of file
diff --git a/question/type/multianswer/edit_multianswer_form.php b/question/type/multianswer/edit_multianswer_form.php
new file mode 100644 (file)
index 0000000..0a32f16
--- /dev/null
@@ -0,0 +1,23 @@
+<?php
+/**
+ * Defines the editing form for the multianswer question type.
+ *
+ * @copyright &copy; 2007 Jamie Pratt
+ * @author Jamie Pratt me@jamiep.org
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package questions
+ */
+
+/**
+ * multianswer editing form definition.
+ */
+class question_edit_multianswer_form extends question_edit_form {
+
+    // No question-type specific form fields.
+
+
+    function qtype() {
+        return 'multianswer';
+    }
+}
+?>
\ No newline at end of file
diff --git a/question/type/multichoice/edit_multichoice_form.php b/question/type/multichoice/edit_multichoice_form.php
new file mode 100644 (file)
index 0000000..e6d08e9
--- /dev/null
@@ -0,0 +1,109 @@
+<?php
+/**
+ * Defines the editing form for the multichoice question type.
+ *
+ * @copyright &copy; 2007 Jamie Pratt
+ * @author Jamie Pratt me@jamiep.org
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package questions
+ */
+
+/**
+ * multiple choice editing form definition.
+ */
+class question_edit_multichoice_form extends question_edit_form {
+    /**
+     * Add question-type specific form fields.
+     *
+     * @param object $mform the form being built.
+     */
+    function definition_inner(&$mform) {
+        $menu = array(get_string('answersingleno', 'qtype_multichoice'), get_string('answersingleyes', 'qtype_multichoice'));
+        $mform->addElement('select', 'single', get_string('answerhowmany', 'qtype_multichoice'), $menu);
+
+        $mform->addElement('selectyesno', 'shuffleanswers', get_string('shuffleanswers', 'qtype_multichoice'));
+        $mform->setHelpButton('shuffleanswers', array('multichoiceshuffle', get_string('shuffleanswers','qtype_multichoice'), 'quiz'));
+
+/*        $mform->addElement('static', 'answersinstruct', get_string('choices', 'qtype_multichoice'), get_string('fillouttwochoices', 'qtype_multichoice'));
+        $mform->closeHeaderBefore('answersinstruct');
+*/
+        $creategrades = get_grade_options();
+        $gradeoptions = $creategrades->gradeoptionsfull;
+        $repeated = array();
+        $repeated[] =& $mform->createElement('header', 'choicehdr', get_string('choiceno', 'qtype_multichoice', '{no}'));
+        $repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'));
+        $repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
+        $repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'));
+
+        if (isset($this->question->options)){
+            $countanswers = count($this->question->options->answers);
+        } else {
+            $countanswers = 0;
+        }
+        $repeatsatstart = (QUESTION_NUMANS_START > ($countanswers + QUESTION_NUMANS_ADD))?
+                            QUESTION_NUMANS_START : ($countanswers + QUESTION_NUMANS_ADD);
+        $repeatedoptions = array();
+        $repeatedoptions['answer']['type'] = PARAM_TEXT;
+        $repeatedoptions['fraction']['default'] = 0;
+        $this->repeat_elements($repeated, $repeatsatstart, $repeatedoptions, 'noanswers', 'addanswers', QUESTION_NUMANS_ADD, get_string('addmorechoiceblanks', 'qtype_multichoice'));
+
+        $mform->addElement('header', 'overallfeedbackhdr', get_string('overallfeedback', 'qtype_multichoice'));
+
+        $mform->addElement('htmleditor', 'correctfeedback', get_string('correctfeedback', 'qtype_multichoice'));
+        $mform->setType('correctfeedback', PARAM_RAW);
+
+        $mform->addElement('htmleditor', 'partiallycorrectfeedback', get_string('partiallycorrectfeedback', 'qtype_multichoice'));
+        $mform->setType('partiallycorrectfeedback', PARAM_RAW);
+
+        $mform->addElement('htmleditor', 'incorrectfeedback', get_string('incorrectfeedback', 'qtype_multichoice'));
+        $mform->setType('incorrectfeedback', PARAM_RAW);
+
+    }
+
+    function set_defaults($question) {
+        if (isset($question->options)){
+            $answers = $question->options->answers;
+            if (count($answers)) {
+                $key = 0;
+                foreach ($answers as $answer){
+                    $default_values['answer['.$key.']'] = $answer->answer;
+                    $default_values['fraction['.$key.']'] = $answer->fraction;
+                    $default_values['feedback['.$key.']'] = $answer->feedback;
+                    $key++;
+                }
+            }
+            $default_values['single'] =  $question->options->single;
+            $default_values['shuffleanswers'] =  $question->options->shuffleanswers;
+            $default_values['correctfeedback'] =  $question->options->correctfeedback;
+            $default_values['partiallycorrectfeedback'] =  $question->options->partiallycorrectfeedback;
+            $default_values['overallincorrectfeedback'] =  $question->options->overallincorrectfeedback;
+            $question = (object)((array)$question + $default_values);
+        }
+        parent::set_defaults($question);
+    }
+
+    function qtype() {
+        return 'multichoice';
+    }
+
+    function validation($data){
+        $errors = array();
+        $answers = $data['answer'];
+        $answercount = 0;
+        foreach ($answers as $answer){
+            $trimmedanswer = trim($answer);
+            if (!empty($trimmedanswer)){
+                $answercount++;
+            }
+        }
+        if ($answercount==0){
+            $errors['answer[0]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
+            $errors['answer[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
+        } elseif ($answercount==1){
+            $errors['answer[1]'] = get_string('notenoughanswers', 'qtype_multichoice', 2);
+
+        }
+        return $errors;
+    }
+}
+?>
\ No newline at end of file
index 628917809583d043d7fa8294b5c4900f7356c19c..4e6be5548015b55a5a484f015345c74854339ef9 100644 (file)
@@ -15,13 +15,13 @@ require_once($CFG->libdir . '/questionlib.php');
 
 /**
  * This is the base class for Moodle question types.
- * 
+ *
  * There are detailed comments on each method, explaining what the method is
  * for, and the circumstances under which you might need to override it.
- * 
+ *
  * Note: the questiontype API should NOT be considered stable yet. Very few
  * question tyeps have been produced yet, so we do not yet know all the places
- * where the current API is insufficient. I would rather learn from the 
+ * where the current API is insufficient. I would rather learn from the
  * experiences of the first few question type implementors, and improve the
  * interface to meet their needs, rather the freeze the API prematurely and
  * condem everyone to working round a clunky interface for ever afterwards.
@@ -33,7 +33,7 @@ class default_questiontype {
      *
      * The name returned should coincide with the name of the directory
      * in which this questiontype is located
-     * 
+     *
      * @return string the name of this question type.
      */
     function name() {
@@ -41,22 +41,22 @@ class default_questiontype {
     }
 
     /**
-     * The name this question should appear as in the create new question 
+     * The name this question should appear as in the create new question
      * dropdown.
-     * 
+     *
      * @return mixed the desired string, or false to hide this question type in the menu.
      */
     function menu_name() {
         $name = $this->name();
         $menu_name = get_string($name, 'qtype_' . $name);
         if ($menu_name[0] == '[') {
-            // Legacy behavior, if the string was not in the proper qtype_name 
+            // Legacy behavior, if the string was not in the proper qtype_name
             // language file, look it up in the quiz one.
             $menu_name = get_string($this->name(), 'quiz');
         }
         return $menu_name;
     }
-    
+
     /**
      * @return boolean true if this question can only be graded manually.
      */
@@ -80,19 +80,19 @@ class default_questiontype {
      * @param string $submiturl passed on to the constructor call.
      * @return object an instance of the form definition, or null if one could not be found.
      */
-    function create_editing_form($submiturl) {
+    function create_editing_form($submiturl, $question) {
         global $CFG;
         require_once("{$CFG->dirroot}/question/type/edit_question_form.php");
-        $definition_file = $CFG->dirroot.'/question/type/'.$this->name().'/edit_'.$this->name().'_question_form.php';
+        $definition_file = $CFG->dirroot.'/question/type/'.$this->name().'/edit_'.$this->name().'_form.php';
         if (!(is_readable($definition_file) && is_file($definition_file))) {
             return null;
         }
         require_once($definition_file);
-        $classname = 'edit_'.$this->name().'_question_form';
+        $classname = 'question_edit_'.$this->name().'_form';
         if (!class_exists($classname)) {
             return null;
         }
-        return new $classname($submiturl);
+        return new $classname($submiturl, $question);
     }
 
     /**
@@ -118,7 +118,7 @@ class default_questiontype {
     * @param object $form the form submitted by the teacher
     * @param object $course the course we are in
     * @return object On success, return the new question object. On failure,
-    *       return an object as follows. If the error object has an errors field, 
+    *       return an object as follows. If the error object has an errors field,
     *       display that as an error message. Otherwise, the editing form will be
     *       redisplayed with validation errors, from validation_errors field, which
     *       is itself an object, shown next to the form fields.
@@ -126,7 +126,7 @@ class default_questiontype {
     function save_question($question, $form, $course) {
         // This default implementation is suitable for most
         // question types.
-        
+
         // First, save the basic question itself
         $question->name               = trim($form->name);
         $question->questiontext       = trim($form->questiontext);
@@ -207,7 +207,7 @@ class default_questiontype {
 
         return $question;
     }
-    
+
     /**
     * Saves question-type specific options
     *
@@ -547,13 +547,13 @@ class default_questiontype {
         /* The default implementation should work for most question types
         provided the member functions it calls are overridden where required.
         The layout is determined by the template question.html */
-        
+
         global $CFG;
         $isgraded = question_state_is_graded($state->last_graded);
 
         // If this question is being shown in the context of a quiz
         // get the context so we can determine whether some extra links
-        // should be shown. (Don't show these links during question preview.) 
+        // should be shown. (Don't show these links during question preview.)
         $cm = get_coursemodule_from_instance('quiz', $cmoptions->id);
         if (!empty($cm->id)) {
             $context = get_context_instance(CONTEXT_MODULE, $cm->id);
@@ -562,7 +562,7 @@ class default_questiontype {
         } else {
             $context = get_context_instance(CONTEXT_SYSTEM, SITEID);
         }
-        
+
         // For editing teachers print a link to an editing popup window
         $editlink = '';
         if ($context && has_capability('moodle/question:manage', $context)) {
@@ -584,10 +584,10 @@ class default_questiontype {
             }
             $grade .= $question->maxgrade;
         }
-        
+
         $comment = stripslashes($state->manualcomment);
         $commentlink = '';
-        
+
         if (isset($options->questioncommentlink) && $context && has_capability('mod/quiz:grade', $context)) {
             $strcomment = get_string('commentorgrade', 'quiz');
             $commentlink = '<div class="commentlink">'.link_to_popup_window ($options->questioncommentlink.'?attempt='.$state->attempt.'&amp;question='.$question->id,
@@ -636,7 +636,7 @@ class default_questiontype {
                                            get_string('time'),
                                            );
                 }
-                
+
                 foreach ($states as $st) {
                     $st->responses[''] = $st->answer;
                     $this->restore_session_and_responses($question, $st);
@@ -837,7 +837,7 @@ class default_questiontype {
     * summarizes the student's response in the given $state. This is used for
     * example in the response history table
     * @return string         The summary of the student response
-    * @param object $question 
+    * @param object $question
     * @param object $state   The state whose responses are to be summarized
     * @param int $length     The maximum length of the returned string
     */
@@ -895,7 +895,7 @@ class default_questiontype {
     *                          that it is safe to use.
     * @param object $teststate The state whose responses are to be
     *                          compared. The state will be of the same age or
-    *                          older than $state. If possible, the method should 
+    *                          older than $state. If possible, the method should
     *                          only use the field $teststate->responses, however
     *                          any field that is set up by restore_session_and_responses
     *                          can be used.
@@ -905,7 +905,7 @@ class default_questiontype {
         // arrays. The ordering of the arrays does not matter.
         // Question types may wish to override this (eg. to ignore trailing
         // white space or to make "7.0" and "7" compare equal).
-        
+
         return $state->responses === $teststate->responses;
     }
 
@@ -944,7 +944,7 @@ class default_questiontype {
     function grade_responses(&$question, &$state, $cmoptions) {
         // The default implementation uses the test_response method to
         // compare what the student entered against each of the possible
-        // answers stored in the question, and uses the grade from the 
+        // answers stored in the question, and uses the grade from the
         // first one that matches. It also sets the marks and penalty.
         // This should be good enought for most simple question types.
 
@@ -959,7 +959,7 @@ class default_questiontype {
         // Make sure we don't assign negative or too high marks.
         $state->raw_grade = min(max((float) $state->raw_grade,
                             0.0), 1.0) * $question->maxgrade;
-                            
+
         // Update the penalty.
         $state->penalty = $question->penalty * $question->maxgrade;
 
@@ -1050,7 +1050,7 @@ class default_questiontype {
         if (true) {
             return;
         }
-        
+
         // no need to display replacement options if the question is new
         if(empty($question->id)) {
             return true;
@@ -1118,10 +1118,10 @@ class default_questiontype {
     /**
      * Print the start of the question editing form, including the question category,
      * questionname, questiontext, image, defaultgrade, penalty and generalfeedback fields.
-     * 
+     *
      * Three of the fields, image, defaultgrade, penalty, are optional, and
-     * can be removed from the from using the $hidefields argument. 
-     * 
+     * can be removed from the from using the $hidefields argument.
+     *
      * @param object $question The question object that the form we are printing is for.
      * @param array $err Array of optional error messages to display by each field.
      *          Used when the form is being redisplayed after validation failed.
@@ -1134,7 +1134,7 @@ class default_questiontype {
         global $CFG;
 
         // If you edit this function, you also need to edit random/editquestion.html.
-        
+
         if (!in_array('image', $hidefields)) {
             make_upload_directory("$course->id");    // Just in case
             $coursefiles = get_directory_list("$CFG->dataroot/$course->id", $CFG->moddata);
@@ -1144,15 +1144,15 @@ class default_questiontype {
                 }
             }
         }
-        
+
         include('editquestionstart.html');
     }
-    
+
     /**
      * Print the end of the question editing form, including the submit, copy,
      * and cancel button, and the standard hidden fields like the sesskey and
      * the question type.
-     * 
+     *
      * @param object $question The question object that the form we are printing is for.
      * @param string $submitscript Extra attributes, for example 'onsubmit="myfunction"',
      *          that is added to the HTML of the submit button.
@@ -1161,15 +1161,15 @@ class default_questiontype {
      */
     function print_question_form_end($question, $submitscript = '', $hiddenfields = '') {
         global $USER;
-        
+
         // If you edit this function, you also need to edit random/editquestion.html.
 
         include('editquestionend.html');
     }
-    
+
     /**
      * Call format_text from weblib.php with the options appropriate to question types.
-     * 
+     *
      * @param string $text the text to format.
      * @param integer $text the type of text. Normally $question->questiontextformat.
      * @param object $cmoptions the context the string is being displayed in. Only $cmoptions->course is used.
@@ -1181,7 +1181,7 @@ class default_questiontype {
         $formatoptions->para = false;
         return format_text($text, $textformat, $formatoptions, $cmoptions->course);
     }
-    
+
 /// BACKUP FUNCTIONS ////////////////////////////
 
     /*
@@ -1214,7 +1214,7 @@ class default_questiontype {
     function restore_recode_answer($state, $restore) {
         // There is nothing to decode
         return $state->answer;
-    }    
+    }
 
     //This function restores the question_rqp_states
     function restore_state($state_id,$info,$restore) {
diff --git a/question/type/shortanswer/edit_shortanswer_form.php b/question/type/shortanswer/edit_shortanswer_form.php
new file mode 100644 (file)
index 0000000..6a3cb14
--- /dev/null
@@ -0,0 +1,85 @@
+<?php
+/**
+ * Defines the editing form for the shortanswer question type.
+ *
+ * @copyright &copy; 2007 Jamie Pratt
+ * @author Jamie Pratt me@jamiep.org
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package questions
+ */
+
+/**
+ * shortanswer editing form definition.
+ */
+class question_edit_shortanswer_form extends question_edit_form {
+    /**
+     * Add question-type specific form fields.
+     *
+     * @param MoodleQuickForm $mform the form being built.
+     */
+    function definition_inner(&$mform) {
+        $menu = array(get_string('caseno', 'quiz'), get_string('caseyes', 'quiz'));
+        $mform->addElement('select', 'usecase', get_string('casesensitive', 'quiz'), $menu);
+
+        $mform->addElement('static', 'answersinstruct', get_string('correctanswers', 'quiz'), get_string('filloutoneanswer', 'quiz'));
+        $mform->closeHeaderBefore('answersinstruct');
+
+        $creategrades = get_grade_options();
+        $gradeoptions = $creategrades->gradeoptions;
+        $repeated = array();
+        $repeated[] =& $mform->createElement('header', 'answerhdr', get_string('answerno', 'qtype_shortanswer', '{no}'));
+        $repeated[] =& $mform->createElement('text', 'answer', get_string('answer', 'quiz'));
+        $repeated[] =& $mform->createElement('select', 'fraction', get_string('grade'), $gradeoptions);
+        $repeated[] =& $mform->createElement('htmleditor', 'feedback', get_string('feedback', 'quiz'));
+
+        if (isset($this->question->options)){
+            $countanswers = count($this->question->options->answers);
+        } else {
+            $countanswers = 0;
+        }
+        $repeatsatstart = (QUESTION_NUMANS_START > ($countanswers + QUESTION_NUMANS_ADD))?
+                            QUESTION_NUMANS_START : ($countanswers + QUESTION_NUMANS_ADD);
+        $repeatedoptions = array();
+        $repeatedoptions['answer']['type'] = PARAM_TEXT;
+        $repeatedoptions['fraction']['default'] = 0;
+        $this->repeat_elements($repeated, $repeatsatstart, $repeatedoptions, 'noanswers', 'addanswers', QUESTION_NUMANS_ADD, get_string('addmoreanswerblanks', 'qtype_shortanswer'));
+
+    }
+
+    function set_defaults($question) {
+        if (isset($question->options)){
+            $answers = $question->options->answers;
+            if (count($answers)) {
+                $key = 0;
+                foreach ($answers as $answer){
+                    $default_values['answer['.$key.']'] = $answer->answer;
+                    $default_values['fraction['.$key.']'] = $answer->fraction;
+                    $default_values['feedback['.$key.']'] = $answer->feedback;
+                    $key++;
+                }
+            }
+            $default_values['usecase'] =  $question->options->usecase;
+            $question = (object)((array)$question + $default_values);
+        }
+        parent::set_defaults($question);
+    }
+    function validation($data){
+        $errors = array();
+        $answers = $data['answer'];
+        $answercount = 0;
+        foreach ($answers as $answer){
+            $trimmedanswer = trim($answer);
+            if (!empty($trimmedanswer)){
+                $answercount++;
+            }
+        }
+        if ($answercount==0){
+            $errors['answer[0]'] = get_string('notenoughanswers', 'quiz', 1);
+        }
+        return $errors;
+    }
+    function qtype() {
+        return 'shortanswer';
+    }
+}
+?>
\ No newline at end of file