From f5565b6969b1f1db6efbcfc37a4738c55c6f83d0 Mon Sep 17 00:00:00 2001 From: gustav_delius Date: Wed, 1 Mar 2006 07:36:09 +0000 Subject: [PATCH] Removing some more references to quiz from import/export code --- lib/questionlib.php | 10 + question/category_class.php | 12 +- question/export.php | 12 +- question/format.php | 2 +- question/format/README.txt | 2 +- question/format/aiken/format.php | 2 +- question/format/aon/format.php | 4 +- question/format/blackboard/format.php | 2 +- question/format/coursetestmanager/format.php | 4 +- question/format/examview/format.php | 5 +- question/format/gift/format.php | 2 +- question/format/hotpot/format.php | 1200 +++++++++--------- question/format/learnwise/format.php | 294 ++--- question/format/missingword/format.php | 2 +- question/format/multianswer/format.php | 2 +- question/format/qti2/format.php | 2 +- question/format/webct/format.php | 16 +- question/format/xhtml/format.php | 2 +- question/format/xml/format.php | 2 +- question/import.php | 10 +- 20 files changed, 800 insertions(+), 787 deletions(-) diff --git a/lib/questionlib.php b/lib/questionlib.php index c448e2b298c..7b48023e22a 100644 --- a/lib/questionlib.php +++ b/lib/questionlib.php @@ -913,6 +913,16 @@ function print_question(&$question, &$state, $number, $cmoptions, $options=null) $QTYPES[$question->qtype]->print_question($question, $state, $number, $cmoptions, $options); } +/** +* Saves question options +* +* Simply calls the question type specific save_question_options() method. +*/ +function save_question_options($question) { + global $QTYPES; + + $QTYPES[$question->qtype]->save_question_options($question); +} /** * Gets all teacher stored answers for a given question diff --git a/question/category_class.php b/question/category_class.php index 6cf982cc186..83fc936f498 100644 --- a/question/category_class.php +++ b/question/category_class.php @@ -2,7 +2,7 @@ /** * Class question_category_object * -* Used for handling changes to the quiz categories +* Used for handling changes to the question categories * * @version $Id$ * @author Martin Dougiamas and many others. {@link http://moodle.org} @@ -255,7 +255,7 @@ class question_category_object { $up = $first ? false : true; $down = $last ? false : true; $first = false; - $this->quiz_edit_category_row($category, $depth, $up, $down, $page); + $this->edit_question_category_row($category, $depth, $up, $down, $page); if (isset($category->children)) { $this->build_edit_table_body($category->children, $page, $firstcat, $lastcat, $depth + 1); } @@ -289,7 +289,7 @@ class question_category_object { * @param boolean down can it be moved down? * @param int page page number */ - function quiz_edit_category_row($category, $depth, $up = false, $down = false, $page = 0) { + function edit_question_category_row($category, $depth, $up = false, $down = false, $page = 0) { global $USER; $fill = str_repeat($this->tab, $depth); @@ -546,7 +546,7 @@ class question_category_object { } /** -* Gets quiz categories +* Gets question categories * * @param int parent - if given, restrict records to those with this parent id. * @param string sort - [[sortfield [,sortfield]] {ASC|DESC}] @@ -565,7 +565,7 @@ class question_category_object { /** -* Deletes an existing quiz category +* Deletes an existing question category * * @param int deletecat id of category to delete * @param int destcategoryid id of category which will inherit the orphans of deletecat @@ -740,7 +740,7 @@ class question_category_object { $cat->sortorder = 999; $cat->stamp = make_unique_id_code(); if (!insert_record("question_categories", $cat)) { - error("Could not insert the new quiz category '$newcategory'", "category.php?id={$newcourse}"); + error("Could not insert the new question category '$newcategory'", "category.php?id={$newcourse}"); } else { notify(get_string("categoryadded", "quiz", $newcategory), 'green'); } diff --git a/question/export.php b/question/export.php index 32741285c38..a373554f7bc 100644 --- a/question/export.php +++ b/question/export.php @@ -86,27 +86,27 @@ require("format.php"); // Parent class require("format/$format/format.php"); - $classname = "quiz_format_$format"; - $quiz_format = new $classname(); + $classname = "qformat_$format"; + $qformat = new $classname(); - if (! $quiz_format->exportpreprocess($category, $course)) { // Do anything before that we need to + if (! $qformat->exportpreprocess($category, $course)) { // Do anything before that we need to error("Error occurred during pre-processing!", "$CFG->wwwroot/mod/quiz/export.php?category=$category->id"); } - if (! $quiz_format->exportprocess($exportfilename)) { // Process the export data + if (! $qformat->exportprocess($exportfilename)) { // Process the export data error("Error occurred during processing!", "$CFG->wwwroot/mod/quiz/export.php?category=$category->id"); } - if (! $quiz_format->exportpostprocess()) { // In case anything needs to be done after + if (! $qformat->exportpostprocess()) { // In case anything needs to be done after error("Error occurred during post-processing!", "$CFG->wwwroot/mod/quiz/export.php?category=$category->id"); } echo "
"; // link to download the finished file - $file_ext = $quiz_format->export_file_extension(); + $file_ext = $qformat->export_file_extension(); $download_str = get_string( 'download', 'quiz' ); $downloadextra_str = get_string( 'downloadextra','quiz' ); if ($CFG->slasharguments) { diff --git a/question/format.php b/question/format.php index 53535eff361..5a8115579cf 100644 --- a/question/format.php +++ b/question/format.php @@ -8,7 +8,7 @@ // Included by import.php and export.php -class quiz_default_format { +class qformat_default { var $displayerrors = true; var $category = NULL; diff --git a/question/format/README.txt b/question/format/README.txt index 75ee24e867f..75e497facbb 100644 --- a/question/format/README.txt +++ b/question/format/README.txt @@ -12,7 +12,7 @@ For correct operation the class name must be based on the name of the containing directory, e.g., directory: webct -class: class quiz_format_webct extends quiz_default_format { +class: class qformat_webct extends qformat_default { Most of them are based on the class found in mod/quiz/format.php. See the comments therein for more information. diff --git a/question/format/aiken/format.php b/question/format/aiken/format.php index e6877d6aac7..d6657adc3ad 100644 --- a/question/format/aiken/format.php +++ b/question/format/aiken/format.php @@ -30,7 +30,7 @@ // Based on format.php, included by ../../import.php -class quiz_format_aiken extends quiz_default_format { +class qformat_aiken extends qformat_default { function provide_import() { return true; diff --git a/question/format/aon/format.php b/question/format/aon/format.php index a1ff955cad2..be0059fbdc4 100644 --- a/question/format/aon/format.php +++ b/question/format/aon/format.php @@ -22,7 +22,7 @@ // Based on format.php, included by ../../import.php -class quiz_format_aon extends quiz_default_format { +class qformat_aon extends qformat_default { function provide_import() { return true; @@ -181,7 +181,7 @@ class quiz_format_aon extends quiz_default_format { $question->subanswers[] = addslashes($shortanswer->answer); } - $result = quiz_save_question_options($question); + $result = save_question_options($question); if (!empty($result->error)) { notify("Error: $result->error"); diff --git a/question/format/blackboard/format.php b/question/format/blackboard/format.php index 587901a4dfb..9969343aa62 100644 --- a/question/format/blackboard/format.php +++ b/question/format/blackboard/format.php @@ -11,7 +11,7 @@ require_once ("$CFG->libdir/xmlize.php"); -class quiz_format_blackboard extends quiz_default_format { +class qformat_blackboard extends qformat_default { function provide_import() { return true; diff --git a/question/format/coursetestmanager/format.php b/question/format/coursetestmanager/format.php index a6fd8ca4f22..e2206f915d7 100755 --- a/question/format/coursetestmanager/format.php +++ b/question/format/coursetestmanager/format.php @@ -8,7 +8,7 @@ // Based on format.php, included by ../../import.php require_once($CFG->dirroot.'/lib/uploadlib.php'); -class quiz_format_coursetestmanager extends quiz_default_format { +class qformat_coursetestmanager extends qformat_default { function provide_import() { return true; @@ -248,7 +248,7 @@ class quiz_format_coursetestmanager extends quiz_default_format { } $this->questionids[] = $question->id; // Now to save all the answers and type-specific options - $result = quiz_save_question_options($question); + $result = save_question_options($question); if (!empty($result->error)) { notify($result->error); $this->deletedatabase($filename); diff --git a/question/format/examview/format.php b/question/format/examview/format.php index 6e7bbb0a1ef..0652116c37b 100755 --- a/question/format/examview/format.php +++ b/question/format/examview/format.php @@ -11,6 +11,9 @@ ** Support of rejoinders ** ** $Log$ +** Revision 1.2 2006/03/01 07:36:08 gustav_delius +** Removing some more references to quiz from import/export code +** ** Revision 1.1 2006/02/24 15:14:04 thepurpleblob ** Moving quiz import/export files to new question area. ** @@ -45,7 +48,7 @@ define("MULTIANSWER", "9"); define("CALCULATED", "10"); */ -class quiz_format_examview extends quiz_default_format { +class qformat_examview extends qformat_default { var $qtypes = array('tf' => TRUEFALSE, 'mc' => MULTICHOICE, diff --git a/question/format/gift/format.php b/question/format/gift/format.php index e95394be111..83cdc7af9d0 100755 --- a/question/format/gift/format.php +++ b/question/format/gift/format.php @@ -32,7 +32,7 @@ ////////////////////////////////////////////////////////////////////////// // Based on default.php, included by ../import.php -class quiz_format_gift extends quiz_default_format { +class qformat_gift extends qformat_default { function provide_import() { return true; diff --git a/question/format/hotpot/format.php b/question/format/hotpot/format.php index 4c06fcfa5d5..47aa7841272 100644 --- a/question/format/hotpot/format.php +++ b/question/format/hotpot/format.php @@ -1,600 +1,600 @@ -quiztype = ''; - $keys = array_keys($xml->xml); - foreach ($keys as $key) { - if (preg_match('/^(hotpot|textoys)-(\w+)-file$/i', $key, $matches)) { - $xml->quiztype = strtolower($matches[2]); - $xml->xml_root = "['$key']['#']"; - break; - } - } - - // convert xml to questions array - $questions = array(); - switch ($xml->quiztype) { - case 'jcloze': - $this->process_jcloze($xml, $questions); - break; - case 'jcross': - $this->process_jcross($xml, $questions); - break; - case 'jmatch': - $this->process_jmatch($xml, $questions); - break; - case 'jmix': - $this->process_jmix($xml, $questions); - break; - case 'jbc': - case 'jquiz': - $this->process_jquiz($xml, $questions); - break; - default: - if (empty($xml->quiztype)) { - notice("Input file not recognized as a Hot Potatoes XML file"); - } else { - notice("Unknown quiz type '$xml->quiztype'"); - } - } // end switch - return $questions; - } - - function process_jcloze(&$xml, &$questions) { - // define default grade (per cloze gap) - $defaultgrade = 1; - $gap_count = 0; - - // detect old Moodles (1.4 and earlier) - global $CFG, $db; - $moodle_14 = false; - if ($columns = $db->MetaColumns("{$CFG->prefix}quiz_multianswers")) { - foreach ($columns as $column) { - if ($column->name=='answers' || $column->name=='positionkey' || $column->name=='answertype' || $column->name=='norm') { - $moodle_14 = true; - } - } - } - - // xml tags for the start of the gap-fill exercise - $tags = 'data,gap-fill'; - - $x = 0; - while (($exercise = "[$x]['#']") && $xml->xml_value($tags, $exercise)) { - // there is usually only one exercise in a file - - if (method_exists($this, 'defaultquestion')) { - $question = $this->defaultquestion(); - } else { - $question = new stdClass(); - $question->usecase = 0; // Ignore case - $question->image = ""; // No images with this format - } - $question->qtype = MULTIANSWER; - - $question->name = $this->hotpot_get_title($xml, $x); - $question->questiontext = $this->hotpot_get_reading($xml); - - // setup answer arrays - if ($moodle_14) { - $question->answers = array(); - } else { - global $course; // set in mod/quiz/import.php - $question->course = $course->id; - $question->options = new stdClass(); - $question->options->questions = array(); // one for each gap - } - - $q = 0; - while ($text = $xml->xml_value($tags, $exercise."[$q]")) { - // add next bit of text - $question->questiontext .= addslashes($text); - - // check for a gap - $question_record = $exercise."['question-record'][$q]['#']"; - if ($xml->xml_value($tags, $question_record)) { - - // add gap - $gap_count ++; - $positionkey = $q+1; - $question->questiontext .= '{#'.$positionkey.'}'; - - // initialize answer settings - if ($moodle_14) { - $question->answers[$q]->positionkey = $positionkey; - $question->answers[$q]->answertype = SHORTANSWER; - $question->answers[$q]->norm = $defaultgrade; - $question->answers[$q]->alternatives = array(); - } else { - $wrapped = new stdClass(); - $wrapped->qtype = SHORTANSWER; - $wrapped->usecase = 0; - $wrapped->defaultgrade = $defaultgrade; - $wrapped->questiontextformat = 0; - $wrapped->answer = array(); - $wrapped->fraction = array(); - $wrapped->feedback = array(); - $answers = array(); - } - - // add answers - $a = 0; - while (($answer=$question_record."['answer'][$a]['#']") && $xml->xml_value($tags, $answer)) { - $text = addslashes($xml->xml_value($tags, $answer."['text'][0]['#']")); - $correct = $xml->xml_value($tags, $answer."['correct'][0]['#']"); - $feedback = addslashes($xml->xml_value($tags, $answer."['feedback'][0]['#']")); - if ($text) { - // set score (0=0%, 1=100%) - $fraction = empty($correct) ? 0 : 1; - // store answer - if ($moodle_14) { - $question->answers[$q]->alternatives[$a] = new stdClass(); - $question->answers[$q]->alternatives[$a]->answer = $text; - $question->answers[$q]->alternatives[$a]->fraction = $fraction; - $question->answers[$q]->alternatives[$a]->feedback = $feedback; - } else { - $wrapped->answer[] = $text; - $wrapped->fraction[] = $fraction; - $wrapped->feedback[] = $feedback; - $answers[] = (empty($fraction) ? '' : '=').$text.(empty($feedback) ? '' : ('#'.$feedback)); - } - } - $a++; - } - // compile answers into question text, if necessary - if ($moodle_14) { - // do nothing - } else { - $wrapped->questiontext = '{'.$defaultgrade.':SHORTANSWER:'.implode('~', $answers).'}'; - $question->options->questions[] = $wrapped; - } - } // end if gap - $q++; - } // end while $text - - // define total grade for this exercise - $question->defaultgrade = $gap_count * $defaultgrade; - - $questions[] = $question; - $x++; - } // end while $exercise - } - - function process_jcross(&$xml, &$questions) { - // xml tags to the start of the crossword exercise clue items - $tags = 'data,crossword,clues,item'; - - $x = 0; - while (($item = "[$x]['#']") && $xml->xml_value($tags, $item)) { - - $text = $xml->xml_value($tags, $item."['def'][0]['#']"); - $answer = $xml->xml_value($tags, $item."['word'][0]['#']"); - - if ($text && $answer) { - if (method_exists($this, 'defaultquestion')) { - $question = $this->defaultquestion(); - } else { - $question = new stdClass(); - $question->usecase = 0; // Ignore case - $question->image = ""; // No images with this format - } - $question->qtype = SHORTANSWER; - $question->name = $this->hotpot_get_title($xml, $x, true); - - $question->questiontext = addslashes($text); - $question->answer = array(addslashes($answer)); - $question->fraction = array(1); - $question->feedback = array(''); - - $questions[] = $question; - } - $x++; - } - } - - function process_jmatch(&$xml, &$questions) { - // define default grade (per matched pair) - $defaultgrade = 1; - $match_count = 0; - - // xml tags to the start of the matching exercise - $tags = 'data,matching-exercise'; - - $x = 0; - while (($exercise = "[$x]['#']") && $xml->xml_value($tags, $exercise)) { - // there is usually only one exercise in a file - - if (method_exists($this, 'defaultquestion')) { - $question = $this->defaultquestion(); - } else { - $question = new stdClass(); - $question->usecase = 0; // Ignore case - $question->image = ""; // No images with this format - } - $question->qtype = MATCH; - $question->name = $this->hotpot_get_title($xml, $x); - - $question->questiontext = $this->hotpot_get_reading($xml); - $question->questiontext .= $this->hotpot_get_instructions($xml); - - $question->subquestions = array(); - $question->subanswers = array(); - $p = 0; - while (($pair = $exercise."['pair'][$p]['#']") && $xml->xml_value($tags, $pair)) { - $left = $xml->xml_value($tags, $pair."['left-item'][0]['#']['text'][0]['#']"); - $right = $xml->xml_value($tags, $pair."['right-item'][0]['#']['text'][0]['#']"); - if ($left && $right) { - $match_count++; - $question->subquestions[$p] = addslashes($left); - $question->subanswers[$p] = addslashes($right); - } - $p++; - } - $question->defaultgrade = $match_count * $defaultgrade; - $questions[] = $question; - $x++; - } - } - - function process_jmix(&$xml, &$questions) { - // define default grade (per segment) - $defaultgrade = 1; - $segment_count = 0; - - // xml tags to the start of the jumbled order exercise - $tags = 'data,jumbled-order-exercise'; - - $x = 0; - while (($exercise = "[$x]['#']") && $xml->xml_value($tags, $exercise)) { - // there is usually only one exercise in a file - - if (method_exists($this, 'defaultquestion')) { - $question = $this->defaultquestion(); - } else { - $question = new stdClass(); - $question->usecase = 0; // Ignore case - $question->image = ""; // No images with this format - } - $question->qtype = SHORTANSWER; - $question->name = $this->hotpot_get_title($xml, $x); - - $question->answer = array(); - $question->fraction = array(); - $question->feedback = array(); - - $i = 0; - $segments = array(); - while ($segment = $xml->xml_value($tags, $exercise."['main-order'][0]['#']['segment'][$i]['#']")) { - $segments[] = addslashes($segment); - $segment_count++; - $i++; - } - $answer = implode(' ', $segments); - - $this->hotpot_seed_RNG(); - shuffle($segments); - - $question->questiontext = $this->hotpot_get_reading($xml); - $question->questiontext .= $this->hotpot_get_instructions($xml); - $question->questiontext .= '   [   '.implode('   ', $segments).'   ]'; - - $a = 0; - while (!empty($answer)) { - $question->answer[$a] = $answer; - $question->fraction[$a] = 1; - $question->feedback[$a] = ''; - $answer = addslashes($xml->xml_value($tags, $exercise."['alternate'][$a]['#']")); - $a++; - } - $question->defaultgrade = $segment_count * $defaultgrade; - $questions[] = $question; - $x++; - } - } - function process_jquiz(&$xml, &$questions) { - // define default grade (per question) - $defaultgrade = 1; - - // xml tags to the start of the questions - $tags = 'data,questions'; - - $x = 0; - while (($exercise = "[$x]['#']") && $xml->xml_value($tags, $exercise)) { - // there is usually only one 'questions' object in a single exercise - - $q = 0; - while (($question_record = $exercise."['question-record'][$q]['#']") && $xml->xml_value($tags, $question_record)) { - - if (method_exists($this, 'defaultquestion')) { - $question = $this->defaultquestion(); - } else { - $question = new stdClass(); - $question->usecase = 0; // Ignore case - $question->image = ""; // No images with this format - } - $question->defaultgrade = $defaultgrade; - $question->name = $this->hotpot_get_title($xml, $q, true); - - $text = $xml->xml_value($tags, $question_record."['question'][0]['#']"); - $question->questiontext = addslashes($text); - - if ($xml->xml_value($tags, $question_record."['answers']")) { - // HP6 JQuiz - $answers = $question_record."['answers'][0]['#']"; - } else { - // HP5 JBC or JQuiz - $answers = $question_record; - } - if($xml->xml_value($tags, $question_record."['question-type']")) { - // HP6 JQuiz - $type = $xml->xml_value($tags, $question_record."['question-type'][0]['#']"); - // 1 : multiple choice - // 2 : short-answer - // 3 : hybrid - // 4 : multiple select - } else { - // HP5 - switch ($xml->quiztype) { - case 'jbc': - $must_select_all = $xml->xml_value($tags, $question_record."['must-select-all'][0]['#']"); - if (empty($must_select_all)) { - $type = 1; // multichoice - } else { - $type = 4; // multiselect - } - break; - case 'jquiz': - $type = 2; // shortanswer - break; - default: - $type = 0; // unknown - } - } - $question->qtype = ($type==2 ? SHORTANSWER : MULTICHOICE); - $question->single = ($type==4 ? 0 : 1); - - // workaround required to calculate scores for multiple select answers - $no_of_correct_answers = 0; - if ($type==4) { - $a = 0; - while (($answer = $answers."['answer'][$a]['#']") && $xml->xml_value($tags, $answer)) { - $correct = $xml->xml_value($tags, $answer."['correct'][0]['#']"); - if (empty($correct)) { - // do nothing - } else { - $no_of_correct_answers++; - } - $a++; - } - } - $a = 0; - $question->answer = array(); - $question->fraction = array(); - $question->feedback = array(); - while (($answer = $answers."['answer'][$a]['#']") && $xml->xml_value($tags, $answer)) { - $correct = $xml->xml_value($tags, $answer."['correct'][0]['#']"); - if (empty($correct)) { - $fraction = 0; - } else if ($type==4) { // multiple select - // strange behavior if the $fraction isn't exact to 5 decimal places - $fraction = round(1/$no_of_correct_answers, 5); - } else { - if ($xml->xml_value($tags, $answer."['percent-correct']")) { - // HP6 JQuiz - $percent = $xml->xml_value($tags, $answer."['percent-correct'][0]['#']"); - $fraction = $percent/100; - } else { - // HP5 JBC or JQuiz - $fraction = 1; - } - } - $question->fraction[] = $fraction; - $question->feedback[] = addslashes($xml->xml_value($tags, $answer."['feedback'][0]['#']")); - $question->answer[] = addslashes($xml->xml_value($tags, $answer."['text'][0]['#']")); - $a++; - } - $questions[] = $question; - $q++; - } - $x++; - } - } - - function hotpot_seed_RNG() { - // seed the random number generator - static $HOTPOT_SEEDED_RNG = FALSE; - if (!$HOTPOT_SEEDED_RNG) { - srand((double) microtime() * 1000000); - $HOTPOT_SEEDED_RNG = TRUE; - } - } - function hotpot_get_title(&$xml, $x, $flag=false) { - $title = $xml->xml_value('data,title'); - if ($x || $flag) { - $title .= ' ('.($x+1).')'; - } - return addslashes($title); - } - function hotpot_get_instructions(&$xml) { - $text = $xml->xml_value('hotpot-config-file,instructions'); - if (empty($text)) { - $text = "Hot Potatoes $xml->quiztype"; - } - return addslashes($text); - } - function hotpot_get_reading(&$xml) { - $str = ''; - $tags = 'data,reading'; - if ($xml->xml_value("$tags,include-reading")) { - if ($title = $xml->xml_value("$tags,reading-title")) { - $str .= "

$title

"; - } - if ($text = $xml->xml_value("$tags,reading-text")) { - $str .= "

$text

"; - } - } - return addslashes($str); - } -} // end class - -// get the standard XML parser supplied with Moodle -require_once("$CFG->libdir/xmlize.php"); - -class hotpot_xml_tree { - function hotpot_xml_tree($str, $xml_root='') { - if (empty($str)) { - $this->xml = array(); - } else { - // encode htmlentities in JCloze - $this->encode_cdata($str, 'gap-fill'); - // encode as utf8 - $str = utf8_encode($str); - // xmlize (=convert xml to tree) - $this->xml = xmlize($str, 0); - } - $this->xml_root = $xml_root; - } - function xml_value($tags, $more_tags="[0]['#']") { - - $tags = empty($tags) ? '' : "['".str_replace(",", "'][0]['#']['", $tags)."']"; - eval('$value = &$this->xml'.$this->xml_root.$tags.$more_tags.';'); - - if (is_string($value)) { - $value = utf8_decode($value); - - // decode angle brackets and ampersands - $value = strtr($value, array('<'=>'<', '>'=>'>', '&'=>'&')); - - // remove white space between , and parts - // (so it doesn't get converted to
) - $htmltags = '(' - . 'TABLE|/?CAPTION|/?COL|/?COLGROUP|/?TBODY|/?TFOOT|/?THEAD|/?TD|/?TH|/?TR' - . '|OL|UL|/?LI' - . '|DL|/?DT|/?DD' - . '|EMBED|OBJECT|APPLET|/?PARAM' - //. '|SELECT|/?OPTION' - //. '|FIELDSET|/?LEGEND' - //. '|FRAMESET|/?FRAME' - . ')' - ; - $search = '#(<'.$htmltags.'[^>]*'.'>)\s+'.'(?='.'<'.')#is'; - $value = preg_replace($search, '\\1', $value); - - // replace remaining newlines with
- $value = str_replace("\n", '
', $value); - - // encode unicode characters as HTML entities - // (in particular, accented charaters that have not been encoded by HP) - - // multibyte unicode characters can be detected by checking the hex value of the first character - // 00 - 7F : ascii char (roman alphabet + punctuation) - // 80 - BF : byte 2, 3 or 4 of a unicode char - // C0 - DF : 1st byte of 2-byte char - // E0 - EF : 1st byte of 3-byte char - // F0 - FF : 1st byte of 4-byte char - // if the string doesn't match the above, it might be - // 80 - FF : single-byte, non-ascii char - $search = '#('.'[\xc0-\xdf][\x80-\xbf]'.'|'.'[\xe0-\xef][\x80-\xbf]{2}'.'|'.'[\xf0-\xff][\x80-\xbf]{3}'.'|'.'[\x80-\xff]'.')#se'; - $value = preg_replace($search, "hotpot_utf8_to_html_entity('\\1')", $value); - } - return $value; - } - function encode_cdata(&$str, $tag) { - - // conversion tables - static $HTML_ENTITIES = array( - ''' => "'", - '"' => '"', - '<' => '<', - '>' => '>', - '&' => '&', - ); - static $ILLEGAL_STRINGS = array( - "\r" => '', - "\n" => '<br />', - ']]>' => ']]>', - ); - - // extract the $tag from the $str(ing), if possible - $pattern = '|(^.*<'.$tag.'[^>]*)(>.*<)(/'.$tag.'>.*$)|is'; - if (preg_match($pattern, $str, $matches)) { - - // encode problematic CDATA chars and strings - $matches[2] = strtr($matches[2], $ILLEGAL_STRINGS); - - - // if there are any ampersands in "open text" - // surround them by CDATA start and end markers - // (and convert HTML entities to plain text) - $search = '/>([^<]*&[^<]*)0, 2=>192, 3=>224, 4=>240 - ); - - // the number of bits to shift each character by - static $HOTPOT_UTF8_SHIFT = array( - 1=>array(0=>0), - 2=>array(0=>6, 1=>0), - 3=>array(0=>12, 1=>6, 2=>0), - 4=>array(0=>18, 1=>12, 2=>6, 3=>0) - ); - - $dec = 0; - $len = strlen($char); - for ($pos=0; $pos<$len; $pos++) { - $ord = ord ($char{$pos}); - $ord -= ($pos ? 128 : $HOTPOT_UTF8_DECREMENT[$len]); - $dec += ($ord << $HOTPOT_UTF8_SHIFT[$len][$pos]); - } - return '&#x'.sprintf('%04X', $dec).';'; -} - -// allow importing in Moodle v1.4 (and less) -// same core functions but different class name -if (!class_exists("quiz_file_format")) { - class quiz_file_format extends quiz_default_format { - function readquestions ($lines) { - $format = new quiz_format_hotpot(); - return $format->readquestions($lines); - } - } -} - -?> +quiztype = ''; + $keys = array_keys($xml->xml); + foreach ($keys as $key) { + if (preg_match('/^(hotpot|textoys)-(\w+)-file$/i', $key, $matches)) { + $xml->quiztype = strtolower($matches[2]); + $xml->xml_root = "['$key']['#']"; + break; + } + } + + // convert xml to questions array + $questions = array(); + switch ($xml->quiztype) { + case 'jcloze': + $this->process_jcloze($xml, $questions); + break; + case 'jcross': + $this->process_jcross($xml, $questions); + break; + case 'jmatch': + $this->process_jmatch($xml, $questions); + break; + case 'jmix': + $this->process_jmix($xml, $questions); + break; + case 'jbc': + case 'jquiz': + $this->process_jquiz($xml, $questions); + break; + default: + if (empty($xml->quiztype)) { + notice("Input file not recognized as a Hot Potatoes XML file"); + } else { + notice("Unknown quiz type '$xml->quiztype'"); + } + } // end switch + return $questions; + } + + function process_jcloze(&$xml, &$questions) { + // define default grade (per cloze gap) + $defaultgrade = 1; + $gap_count = 0; + + // detect old Moodles (1.4 and earlier) + global $CFG, $db; + $moodle_14 = false; + if ($columns = $db->MetaColumns("{$CFG->prefix}quiz_multianswers")) { + foreach ($columns as $column) { + if ($column->name=='answers' || $column->name=='positionkey' || $column->name=='answertype' || $column->name=='norm') { + $moodle_14 = true; + } + } + } + + // xml tags for the start of the gap-fill exercise + $tags = 'data,gap-fill'; + + $x = 0; + while (($exercise = "[$x]['#']") && $xml->xml_value($tags, $exercise)) { + // there is usually only one exercise in a file + + if (method_exists($this, 'defaultquestion')) { + $question = $this->defaultquestion(); + } else { + $question = new stdClass(); + $question->usecase = 0; // Ignore case + $question->image = ""; // No images with this format + } + $question->qtype = MULTIANSWER; + + $question->name = $this->hotpot_get_title($xml, $x); + $question->questiontext = $this->hotpot_get_reading($xml); + + // setup answer arrays + if ($moodle_14) { + $question->answers = array(); + } else { + global $course; // set in mod/quiz/import.php + $question->course = $course->id; + $question->options = new stdClass(); + $question->options->questions = array(); // one for each gap + } + + $q = 0; + while ($text = $xml->xml_value($tags, $exercise."[$q]")) { + // add next bit of text + $question->questiontext .= addslashes($text); + + // check for a gap + $question_record = $exercise."['question-record'][$q]['#']"; + if ($xml->xml_value($tags, $question_record)) { + + // add gap + $gap_count ++; + $positionkey = $q+1; + $question->questiontext .= '{#'.$positionkey.'}'; + + // initialize answer settings + if ($moodle_14) { + $question->answers[$q]->positionkey = $positionkey; + $question->answers[$q]->answertype = SHORTANSWER; + $question->answers[$q]->norm = $defaultgrade; + $question->answers[$q]->alternatives = array(); + } else { + $wrapped = new stdClass(); + $wrapped->qtype = SHORTANSWER; + $wrapped->usecase = 0; + $wrapped->defaultgrade = $defaultgrade; + $wrapped->questiontextformat = 0; + $wrapped->answer = array(); + $wrapped->fraction = array(); + $wrapped->feedback = array(); + $answers = array(); + } + + // add answers + $a = 0; + while (($answer=$question_record."['answer'][$a]['#']") && $xml->xml_value($tags, $answer)) { + $text = addslashes($xml->xml_value($tags, $answer."['text'][0]['#']")); + $correct = $xml->xml_value($tags, $answer."['correct'][0]['#']"); + $feedback = addslashes($xml->xml_value($tags, $answer."['feedback'][0]['#']")); + if ($text) { + // set score (0=0%, 1=100%) + $fraction = empty($correct) ? 0 : 1; + // store answer + if ($moodle_14) { + $question->answers[$q]->alternatives[$a] = new stdClass(); + $question->answers[$q]->alternatives[$a]->answer = $text; + $question->answers[$q]->alternatives[$a]->fraction = $fraction; + $question->answers[$q]->alternatives[$a]->feedback = $feedback; + } else { + $wrapped->answer[] = $text; + $wrapped->fraction[] = $fraction; + $wrapped->feedback[] = $feedback; + $answers[] = (empty($fraction) ? '' : '=').$text.(empty($feedback) ? '' : ('#'.$feedback)); + } + } + $a++; + } + // compile answers into question text, if necessary + if ($moodle_14) { + // do nothing + } else { + $wrapped->questiontext = '{'.$defaultgrade.':SHORTANSWER:'.implode('~', $answers).'}'; + $question->options->questions[] = $wrapped; + } + } // end if gap + $q++; + } // end while $text + + // define total grade for this exercise + $question->defaultgrade = $gap_count * $defaultgrade; + + $questions[] = $question; + $x++; + } // end while $exercise + } + + function process_jcross(&$xml, &$questions) { + // xml tags to the start of the crossword exercise clue items + $tags = 'data,crossword,clues,item'; + + $x = 0; + while (($item = "[$x]['#']") && $xml->xml_value($tags, $item)) { + + $text = $xml->xml_value($tags, $item."['def'][0]['#']"); + $answer = $xml->xml_value($tags, $item."['word'][0]['#']"); + + if ($text && $answer) { + if (method_exists($this, 'defaultquestion')) { + $question = $this->defaultquestion(); + } else { + $question = new stdClass(); + $question->usecase = 0; // Ignore case + $question->image = ""; // No images with this format + } + $question->qtype = SHORTANSWER; + $question->name = $this->hotpot_get_title($xml, $x, true); + + $question->questiontext = addslashes($text); + $question->answer = array(addslashes($answer)); + $question->fraction = array(1); + $question->feedback = array(''); + + $questions[] = $question; + } + $x++; + } + } + + function process_jmatch(&$xml, &$questions) { + // define default grade (per matched pair) + $defaultgrade = 1; + $match_count = 0; + + // xml tags to the start of the matching exercise + $tags = 'data,matching-exercise'; + + $x = 0; + while (($exercise = "[$x]['#']") && $xml->xml_value($tags, $exercise)) { + // there is usually only one exercise in a file + + if (method_exists($this, 'defaultquestion')) { + $question = $this->defaultquestion(); + } else { + $question = new stdClass(); + $question->usecase = 0; // Ignore case + $question->image = ""; // No images with this format + } + $question->qtype = MATCH; + $question->name = $this->hotpot_get_title($xml, $x); + + $question->questiontext = $this->hotpot_get_reading($xml); + $question->questiontext .= $this->hotpot_get_instructions($xml); + + $question->subquestions = array(); + $question->subanswers = array(); + $p = 0; + while (($pair = $exercise."['pair'][$p]['#']") && $xml->xml_value($tags, $pair)) { + $left = $xml->xml_value($tags, $pair."['left-item'][0]['#']['text'][0]['#']"); + $right = $xml->xml_value($tags, $pair."['right-item'][0]['#']['text'][0]['#']"); + if ($left && $right) { + $match_count++; + $question->subquestions[$p] = addslashes($left); + $question->subanswers[$p] = addslashes($right); + } + $p++; + } + $question->defaultgrade = $match_count * $defaultgrade; + $questions[] = $question; + $x++; + } + } + + function process_jmix(&$xml, &$questions) { + // define default grade (per segment) + $defaultgrade = 1; + $segment_count = 0; + + // xml tags to the start of the jumbled order exercise + $tags = 'data,jumbled-order-exercise'; + + $x = 0; + while (($exercise = "[$x]['#']") && $xml->xml_value($tags, $exercise)) { + // there is usually only one exercise in a file + + if (method_exists($this, 'defaultquestion')) { + $question = $this->defaultquestion(); + } else { + $question = new stdClass(); + $question->usecase = 0; // Ignore case + $question->image = ""; // No images with this format + } + $question->qtype = SHORTANSWER; + $question->name = $this->hotpot_get_title($xml, $x); + + $question->answer = array(); + $question->fraction = array(); + $question->feedback = array(); + + $i = 0; + $segments = array(); + while ($segment = $xml->xml_value($tags, $exercise."['main-order'][0]['#']['segment'][$i]['#']")) { + $segments[] = addslashes($segment); + $segment_count++; + $i++; + } + $answer = implode(' ', $segments); + + $this->hotpot_seed_RNG(); + shuffle($segments); + + $question->questiontext = $this->hotpot_get_reading($xml); + $question->questiontext .= $this->hotpot_get_instructions($xml); + $question->questiontext .= '   [   '.implode('   ', $segments).'   ]'; + + $a = 0; + while (!empty($answer)) { + $question->answer[$a] = $answer; + $question->fraction[$a] = 1; + $question->feedback[$a] = ''; + $answer = addslashes($xml->xml_value($tags, $exercise."['alternate'][$a]['#']")); + $a++; + } + $question->defaultgrade = $segment_count * $defaultgrade; + $questions[] = $question; + $x++; + } + } + function process_jquiz(&$xml, &$questions) { + // define default grade (per question) + $defaultgrade = 1; + + // xml tags to the start of the questions + $tags = 'data,questions'; + + $x = 0; + while (($exercise = "[$x]['#']") && $xml->xml_value($tags, $exercise)) { + // there is usually only one 'questions' object in a single exercise + + $q = 0; + while (($question_record = $exercise."['question-record'][$q]['#']") && $xml->xml_value($tags, $question_record)) { + + if (method_exists($this, 'defaultquestion')) { + $question = $this->defaultquestion(); + } else { + $question = new stdClass(); + $question->usecase = 0; // Ignore case + $question->image = ""; // No images with this format + } + $question->defaultgrade = $defaultgrade; + $question->name = $this->hotpot_get_title($xml, $q, true); + + $text = $xml->xml_value($tags, $question_record."['question'][0]['#']"); + $question->questiontext = addslashes($text); + + if ($xml->xml_value($tags, $question_record."['answers']")) { + // HP6 JQuiz + $answers = $question_record."['answers'][0]['#']"; + } else { + // HP5 JBC or JQuiz + $answers = $question_record; + } + if($xml->xml_value($tags, $question_record."['question-type']")) { + // HP6 JQuiz + $type = $xml->xml_value($tags, $question_record."['question-type'][0]['#']"); + // 1 : multiple choice + // 2 : short-answer + // 3 : hybrid + // 4 : multiple select + } else { + // HP5 + switch ($xml->quiztype) { + case 'jbc': + $must_select_all = $xml->xml_value($tags, $question_record."['must-select-all'][0]['#']"); + if (empty($must_select_all)) { + $type = 1; // multichoice + } else { + $type = 4; // multiselect + } + break; + case 'jquiz': + $type = 2; // shortanswer + break; + default: + $type = 0; // unknown + } + } + $question->qtype = ($type==2 ? SHORTANSWER : MULTICHOICE); + $question->single = ($type==4 ? 0 : 1); + + // workaround required to calculate scores for multiple select answers + $no_of_correct_answers = 0; + if ($type==4) { + $a = 0; + while (($answer = $answers."['answer'][$a]['#']") && $xml->xml_value($tags, $answer)) { + $correct = $xml->xml_value($tags, $answer."['correct'][0]['#']"); + if (empty($correct)) { + // do nothing + } else { + $no_of_correct_answers++; + } + $a++; + } + } + $a = 0; + $question->answer = array(); + $question->fraction = array(); + $question->feedback = array(); + while (($answer = $answers."['answer'][$a]['#']") && $xml->xml_value($tags, $answer)) { + $correct = $xml->xml_value($tags, $answer."['correct'][0]['#']"); + if (empty($correct)) { + $fraction = 0; + } else if ($type==4) { // multiple select + // strange behavior if the $fraction isn't exact to 5 decimal places + $fraction = round(1/$no_of_correct_answers, 5); + } else { + if ($xml->xml_value($tags, $answer."['percent-correct']")) { + // HP6 JQuiz + $percent = $xml->xml_value($tags, $answer."['percent-correct'][0]['#']"); + $fraction = $percent/100; + } else { + // HP5 JBC or JQuiz + $fraction = 1; + } + } + $question->fraction[] = $fraction; + $question->feedback[] = addslashes($xml->xml_value($tags, $answer."['feedback'][0]['#']")); + $question->answer[] = addslashes($xml->xml_value($tags, $answer."['text'][0]['#']")); + $a++; + } + $questions[] = $question; + $q++; + } + $x++; + } + } + + function hotpot_seed_RNG() { + // seed the random number generator + static $HOTPOT_SEEDED_RNG = FALSE; + if (!$HOTPOT_SEEDED_RNG) { + srand((double) microtime() * 1000000); + $HOTPOT_SEEDED_RNG = TRUE; + } + } + function hotpot_get_title(&$xml, $x, $flag=false) { + $title = $xml->xml_value('data,title'); + if ($x || $flag) { + $title .= ' ('.($x+1).')'; + } + return addslashes($title); + } + function hotpot_get_instructions(&$xml) { + $text = $xml->xml_value('hotpot-config-file,instructions'); + if (empty($text)) { + $text = "Hot Potatoes $xml->quiztype"; + } + return addslashes($text); + } + function hotpot_get_reading(&$xml) { + $str = ''; + $tags = 'data,reading'; + if ($xml->xml_value("$tags,include-reading")) { + if ($title = $xml->xml_value("$tags,reading-title")) { + $str .= "

$title

"; + } + if ($text = $xml->xml_value("$tags,reading-text")) { + $str .= "

$text

"; + } + } + return addslashes($str); + } +} // end class + +// get the standard XML parser supplied with Moodle +require_once("$CFG->libdir/xmlize.php"); + +class hotpot_xml_tree { + function hotpot_xml_tree($str, $xml_root='') { + if (empty($str)) { + $this->xml = array(); + } else { + // encode htmlentities in JCloze + $this->encode_cdata($str, 'gap-fill'); + // encode as utf8 + $str = utf8_encode($str); + // xmlize (=convert xml to tree) + $this->xml = xmlize($str, 0); + } + $this->xml_root = $xml_root; + } + function xml_value($tags, $more_tags="[0]['#']") { + + $tags = empty($tags) ? '' : "['".str_replace(",", "'][0]['#']['", $tags)."']"; + eval('$value = &$this->xml'.$this->xml_root.$tags.$more_tags.';'); + + if (is_string($value)) { + $value = utf8_decode($value); + + // decode angle brackets and ampersands + $value = strtr($value, array('<'=>'<', '>'=>'>', '&'=>'&')); + + // remove white space between
, and parts + // (so it doesn't get converted to
) + $htmltags = '(' + . 'TABLE|/?CAPTION|/?COL|/?COLGROUP|/?TBODY|/?TFOOT|/?THEAD|/?TD|/?TH|/?TR' + . '|OL|UL|/?LI' + . '|DL|/?DT|/?DD' + . '|EMBED|OBJECT|APPLET|/?PARAM' + //. '|SELECT|/?OPTION' + //. '|FIELDSET|/?LEGEND' + //. '|FRAMESET|/?FRAME' + . ')' + ; + $search = '#(<'.$htmltags.'[^>]*'.'>)\s+'.'(?='.'<'.')#is'; + $value = preg_replace($search, '\\1', $value); + + // replace remaining newlines with
+ $value = str_replace("\n", '
', $value); + + // encode unicode characters as HTML entities + // (in particular, accented charaters that have not been encoded by HP) + + // multibyte unicode characters can be detected by checking the hex value of the first character + // 00 - 7F : ascii char (roman alphabet + punctuation) + // 80 - BF : byte 2, 3 or 4 of a unicode char + // C0 - DF : 1st byte of 2-byte char + // E0 - EF : 1st byte of 3-byte char + // F0 - FF : 1st byte of 4-byte char + // if the string doesn't match the above, it might be + // 80 - FF : single-byte, non-ascii char + $search = '#('.'[\xc0-\xdf][\x80-\xbf]'.'|'.'[\xe0-\xef][\x80-\xbf]{2}'.'|'.'[\xf0-\xff][\x80-\xbf]{3}'.'|'.'[\x80-\xff]'.')#se'; + $value = preg_replace($search, "hotpot_utf8_to_html_entity('\\1')", $value); + } + return $value; + } + function encode_cdata(&$str, $tag) { + + // conversion tables + static $HTML_ENTITIES = array( + ''' => "'", + '"' => '"', + '<' => '<', + '>' => '>', + '&' => '&', + ); + static $ILLEGAL_STRINGS = array( + "\r" => '', + "\n" => '<br />', + ']]>' => ']]>', + ); + + // extract the $tag from the $str(ing), if possible + $pattern = '|(^.*<'.$tag.'[^>]*)(>.*<)(/'.$tag.'>.*$)|is'; + if (preg_match($pattern, $str, $matches)) { + + // encode problematic CDATA chars and strings + $matches[2] = strtr($matches[2], $ILLEGAL_STRINGS); + + + // if there are any ampersands in "open text" + // surround them by CDATA start and end markers + // (and convert HTML entities to plain text) + $search = '/>([^<]*&[^<]*)0, 2=>192, 3=>224, 4=>240 + ); + + // the number of bits to shift each character by + static $HOTPOT_UTF8_SHIFT = array( + 1=>array(0=>0), + 2=>array(0=>6, 1=>0), + 3=>array(0=>12, 1=>6, 2=>0), + 4=>array(0=>18, 1=>12, 2=>6, 3=>0) + ); + + $dec = 0; + $len = strlen($char); + for ($pos=0; $pos<$len; $pos++) { + $ord = ord ($char{$pos}); + $ord -= ($pos ? 128 : $HOTPOT_UTF8_DECREMENT[$len]); + $dec += ($ord << $HOTPOT_UTF8_SHIFT[$len][$pos]); + } + return '&#x'.sprintf('%04X', $dec).';'; +} + +// allow importing in Moodle v1.4 (and less) +// same core functions but different class name +if (!class_exists("quiz_file_format")) { + class quiz_file_format extends qformat_default { + function readquestions ($lines) { + $format = new qformat_hotpot(); + return $format->readquestions($lines); + } + } +} + +?> diff --git a/question/format/learnwise/format.php b/question/format/learnwise/format.php index a614e3235bf..8834055d2db 100755 --- a/question/format/learnwise/format.php +++ b/question/format/learnwise/format.php @@ -1,147 +1,147 @@ -readquestion($currentquestion)) { - $questions[] = $question; - $currentquestion = array(); - } - } - return $questions; - } - - function readquestion($lines) { - $text = implode(' ', $lines); - $text = str_replace(array('\t','\n','\r','\''), array('','','','\\\''), $text); - - $startpos = strpos($text, ''); - if ($startpos === false || $endpos === false) { - return false; - } - - preg_match("//i", $text, $matches); - $type = strtolower($matches[1]); // multichoice or multianswerchoice - - $questiontext = $this->unhtmlentities($this->stringbetween($text, '', '')); - $questionhint = $this->unhtmlentities($this->stringbetween($text, '', '')); - $questionaward = $this->stringbetween($text, '', ''); - $optionlist = $this->stringbetween($text, '', ''); - - $optionlist = explode('stringbetween($option, ' correct="', '">'); - $answer = $this->stringbetween($option, '">', ''); - $optionscorrect[$n] = $correct; - $optionstext[$n] = $this->unhtmlentities($answer); - ++$n; - } - } else if ($type == 'multianswerchoice') { - $numcorrect = 0; - $totalaward = 0; - - $optionsaward = array(); - - foreach ($optionlist as $option) { - preg_match("/correct=\"([^\"]*)\"/i", $option, $correctmatch); - preg_match("/award=\"([^\"]*)\"/i", $option, $awardmatch); - - $correct = $correctmatch[1]; - $award = $awardmatch[1]; - if ($correct == 'yes') { - $totalaward += $award; - ++$numcorrect; - } - - $answer = $this->stringbetween($option, '">', ''); - - $optionscorrect[$n] = $correct; - $optionstext[$n] = $this->unhtmlentities($answer); - $optionsaward[$n] = $award; - ++$n; - } - - } else { - echo "

I don't understand this question type (type = $type).

\n"; - } - - $question = $this->defaultquestion(); - $question->qtype = MULTICHOICE; - $question->name = substr($questiontext, 0, 30); - if (strlen($questiontext) > 30) { - $question->name .= '...'; - } - - $question->questiontext = $questiontext; - $question->single = ($type == 'multichoice') ? 1 : 0; - $question->feedback[] = ''; - - $question->fraction = array(); - $question->answer = array(); - for ($n = 0; $n < count($optionstext); ++$n) { - if ($optionstext[$n]) { - if (!isset($numcorrect)) { // single answer - if ($optionscorrect[$n] == 'yes') { - $fraction = (int) $questionaward; - } else { - $fraction = 0; - } - } else { // mulitple answers - if ($optionscorrect[$n] == 'yes') { - $fraction = $optionsaward[$n] / $totalaward; - } else { - $fraction = -$optionsaward[$n] / count($optionstext); - } - } - $question->fraction[] = $fraction; - $question->answer[] = $optionstext[$n]; - $question->feedback[] = ''; // no feedback in this type - } - } - - return $question; - } - - function stringbetween($text, $start, $end) { - $startpos = strpos($text, $start) + strlen($start); - $endpos = strpos($text, $end); - - if ($startpos <= $endpos) { - return substr($text, $startpos, $endpos - $startpos); - } - } - - function unhtmlentities($string) { - $transtable = get_html_translation_table(HTML_ENTITIES); - $transtable = array_flip($transtable); - return strtr($string, $transtable); - } - -} - -?> +readquestion($currentquestion)) { + $questions[] = $question; + $currentquestion = array(); + } + } + return $questions; + } + + function readquestion($lines) { + $text = implode(' ', $lines); + $text = str_replace(array('\t','\n','\r','\''), array('','','','\\\''), $text); + + $startpos = strpos($text, ''); + if ($startpos === false || $endpos === false) { + return false; + } + + preg_match("//i", $text, $matches); + $type = strtolower($matches[1]); // multichoice or multianswerchoice + + $questiontext = $this->unhtmlentities($this->stringbetween($text, '', '')); + $questionhint = $this->unhtmlentities($this->stringbetween($text, '', '')); + $questionaward = $this->stringbetween($text, '', ''); + $optionlist = $this->stringbetween($text, '', ''); + + $optionlist = explode('stringbetween($option, ' correct="', '">'); + $answer = $this->stringbetween($option, '">', ''); + $optionscorrect[$n] = $correct; + $optionstext[$n] = $this->unhtmlentities($answer); + ++$n; + } + } else if ($type == 'multianswerchoice') { + $numcorrect = 0; + $totalaward = 0; + + $optionsaward = array(); + + foreach ($optionlist as $option) { + preg_match("/correct=\"([^\"]*)\"/i", $option, $correctmatch); + preg_match("/award=\"([^\"]*)\"/i", $option, $awardmatch); + + $correct = $correctmatch[1]; + $award = $awardmatch[1]; + if ($correct == 'yes') { + $totalaward += $award; + ++$numcorrect; + } + + $answer = $this->stringbetween($option, '">', ''); + + $optionscorrect[$n] = $correct; + $optionstext[$n] = $this->unhtmlentities($answer); + $optionsaward[$n] = $award; + ++$n; + } + + } else { + echo "

I don't understand this question type (type = $type).

\n"; + } + + $question = $this->defaultquestion(); + $question->qtype = MULTICHOICE; + $question->name = substr($questiontext, 0, 30); + if (strlen($questiontext) > 30) { + $question->name .= '...'; + } + + $question->questiontext = $questiontext; + $question->single = ($type == 'multichoice') ? 1 : 0; + $question->feedback[] = ''; + + $question->fraction = array(); + $question->answer = array(); + for ($n = 0; $n < count($optionstext); ++$n) { + if ($optionstext[$n]) { + if (!isset($numcorrect)) { // single answer + if ($optionscorrect[$n] == 'yes') { + $fraction = (int) $questionaward; + } else { + $fraction = 0; + } + } else { // mulitple answers + if ($optionscorrect[$n] == 'yes') { + $fraction = $optionsaward[$n] / $totalaward; + } else { + $fraction = -$optionsaward[$n] / count($optionstext); + } + } + $question->fraction[] = $fraction; + $question->answer[] = $optionstext[$n]; + $question->feedback[] = ''; // no feedback in this type + } + } + + return $question; + } + + function stringbetween($text, $start, $end) { + $startpos = strpos($text, $start) + strlen($start); + $endpos = strpos($text, $end); + + if ($startpos <= $endpos) { + return substr($text, $startpos, $endpos - $startpos); + } + } + + function unhtmlentities($string) { + $transtable = get_html_translation_table(HTML_ENTITIES); + $transtable = array_flip($transtable); + return strtr($string, $transtable); + } + +} + +?> diff --git a/question/format/missingword/format.php b/question/format/missingword/format.php index a73dbaaa940..dda8d8018df 100644 --- a/question/format/missingword/format.php +++ b/question/format/missingword/format.php @@ -26,7 +26,7 @@ // Based on format.php, included by ../../import.php -class quiz_format_missingword extends quiz_default_format { +class qformat_missingword extends qformat_default { function provide_import() { return true; diff --git a/question/format/multianswer/format.php b/question/format/multianswer/format.php index fdbdf95e1b6..a168cc93d37 100644 --- a/question/format/multianswer/format.php +++ b/question/format/multianswer/format.php @@ -9,7 +9,7 @@ // Based on format.php, included by ../../import.php -class quiz_format_multianswer extends quiz_default_format { +class qformat_multianswer extends qformat_default { function provide_import() { return true; diff --git a/question/format/qti2/format.php b/question/format/qti2/format.php index 5f9b13cebf1..a3907d3e4f2 100644 --- a/question/format/qti2/format.php +++ b/question/format/qti2/format.php @@ -10,7 +10,7 @@ require_once("$CFG->dirroot/question/format/qti2/qt_common.php"); define('CLOZE_TRAILING_TEXT_ID', 9999999); -class quiz_format_qti2 extends quiz_default_format { +class qformat_qti2 extends qformat_default { var $lang; diff --git a/question/format/webct/format.php b/question/format/webct/format.php index 2ce1c08de43..d98f8be7802 100644 --- a/question/format/webct/format.php +++ b/question/format/webct/format.php @@ -58,7 +58,7 @@ function unhtmlentities($string){ return preg_replace ($search, $replace, $string); } -class quiz_format_webct_modified_calculated_qtype extends quiz_calculated_qtype { +class qformat_webct_modified_calculated_qtype extends quiz_calculated_qtype { // We need to make a modification of this qtype so that // it will be able to save webct style calculated questions // The difference between webct and Moodle is that webct @@ -142,9 +142,9 @@ class quiz_format_webct_modified_calculated_qtype extends quiz_calculated_qtype return true; } } -$QTYPES[CALCULATED] = new quiz_format_webct_modified_calculated_qtype(); +$QTYPES[CALCULATED] = new qformat_webct_modified_calculated_qtype(); -function quiz_format_webct_convert_formula($formula) { +function qformat_webct_convert_formula($formula) { // Remove empty space, as it would cause problems otherwise: $formula = str_replace(' ', '', $formula); @@ -239,7 +239,7 @@ function quiz_format_webct_convert_formula($formula) { return $formula; } -class quiz_format_webct extends quiz_default_format { +class qformat_webct extends qformat_default { function provide_import() { return true; @@ -247,7 +247,7 @@ class quiz_format_webct extends quiz_default_format { function readquestions ($lines) { - $qtypecalculated = new quiz_format_webct_modified_calculated_qtype(); + $qtypecalculated = new qformat_webct_modified_calculated_qtype(); $webctnumberregex = '[+-]?([0-9]+(\\.[0-9]*)?|\\.[0-9]+)((e|E|\\*10\\*\\*)([+-]?[0-9]+|\\([+-]?[0-9]+\\)))?'; @@ -506,7 +506,7 @@ class quiz_format_webct extends quiz_default_format { if (CALCULATED == $question->qtype && ereg( "^:([[:lower:]].*|::.*)-(MIN|MAX|DEC|VAL([0-9]+))::?:?($webctnumberregex)", $line, $webct_options)) { $datasetname = ereg_replace('^::', '', $webct_options[1]); - $datasetvalue = quiz_format_webct_convert_formula($webct_options[4]); + $datasetvalue = qformat_webct_convert_formula($webct_options[4]); switch ($webct_options[2]) { case 'MIN': $question->datasets[$datasetname]->min = $datasetvalue; @@ -551,7 +551,7 @@ class quiz_format_webct extends quiz_default_format { // Answer for a CALCULATED question ++$currentchoice; $question->answers[$currentchoice]->answer = - quiz_format_webct_convert_formula($webct_options[1]); + qformat_webct_convert_formula($webct_options[1]); // Default settings: $question->answers[$currentchoice]->fraction = 1.0; @@ -595,7 +595,7 @@ class quiz_format_webct extends quiz_default_format { if (CALCULATED == $question->qtype && eregi("^:TOL:($webctnumberregex)", $line, $webct_options)) { // We can but hope that this always appear before the TOL property $question->answers[$currentchoice]->tolerance = - quiz_format_webct_convert_formula($webct_options[1]); + qformat_webct_convert_formula($webct_options[1]); continue; } diff --git a/question/format/xhtml/format.php b/question/format/xhtml/format.php index a917e3358c6..b69501237b3 100755 --- a/question/format/xhtml/format.php +++ b/question/format/xhtml/format.php @@ -1,7 +1,7 @@ libdir/xmlize.php" ); -class quiz_format_xml extends quiz_default_format { +class qformat_xml extends qformat_default { function provide_import() { return true; diff --git a/question/import.php b/question/import.php index 9b9516f0597..58658867bb6 100644 --- a/question/import.php +++ b/question/import.php @@ -100,20 +100,20 @@ require("format.php"); // Parent class require("format/$format/format.php"); - $classname = "quiz_format_$format"; - $quiz_format = new $classname(); + $classname = "qformat_$format"; + $qformat = new $classname(); - if (! $quiz_format->importpreprocess($category,$course)) { // Do anything before that we need to + if (! $qformat->importpreprocess($category,$course)) { // Do anything before that we need to error("Error occurred during pre-processing!", "$CFG->wwwroot/mod/quiz/import.php?category=$category->id"); } - if (! $quiz_format->importprocess($_FILES['newfile']['tmp_name'])) { // Process the uploaded file + if (! $qformat->importprocess($_FILES['newfile']['tmp_name'])) { // Process the uploaded file error("Error occurred during processing!", "$CFG->wwwroot/mod/quiz/import.php?category=$category->id"); } - if (! $quiz_format->importpostprocess()) { // In case anything needs to be done after + if (! $qformat->importpostprocess()) { // In case anything needs to be done after error("Error occurred during post-processing!", "$CFG->wwwroot/mod/quiz/import.php?category=$category->id"); }