From 05a43d9094e1f8fd5c5dcd2fa1d2a5b839a6921b Mon Sep 17 00:00:00 2001 From: Gordon Bateson Date: Fri, 10 May 2013 13:31:07 +0900 Subject: [PATCH] MDL-79863 qtype_ordering: Moodle.2x question/type/ordering use md5 instead of fraction field as id in ordering questions --- question/type/ordering/edit_ordering_form.php | 55 +++-- question/type/ordering/question.php | 198 +++++++----------- question/type/ordering/questiontype.php | 160 ++++++-------- question/type/ordering/renderer.php | 181 +++++++++------- 4 files changed, 283 insertions(+), 311 deletions(-) diff --git a/question/type/ordering/edit_ordering_form.php b/question/type/ordering/edit_ordering_form.php index 772826653da..247da49a1ee 100644 --- a/question/type/ordering/edit_ordering_form.php +++ b/question/type/ordering/edit_ordering_form.php @@ -34,6 +34,11 @@ defined('MOODLE_INTERNAL') || die(); * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class qtype_ordering_edit_form extends question_edit_form { + + public function qtype() { + return 'ordering'; + } + /** * Add question-type specific form fields. * @@ -43,28 +48,35 @@ class qtype_ordering_edit_form extends question_edit_form { $NUMANS_START = 10; $NUMANS_ADD = 5; - $menu = array(get_string('ordering_exactorder', 'qtype_ordering'), get_string('ordering_relativeorder', 'qtype_ordering'), get_string('ordering_contiguous', 'qtype_ordering')); - $mform->addElement('select', 'logical', get_string('ordering_logicalpossibilities', 'qtype_ordering'), $menu); + $options = array( + 0 => get_string('ordering_exactorder', 'qtype_ordering'), // = all ? + 1 => get_string('ordering_relativeorder', 'qtype_ordering'), // = random subset + 2 => get_string('ordering_contiguous', 'qtype_ordering') // = contiguous subset + ); + $mform->addElement('select', 'logical', get_string('ordering_logicalpossibilities', 'qtype_ordering'), $options); $mform->setDefault('logical', 0); - $menu1[] = "All"; + $options = array(0 => 'All'); for ($i=3; $i <= 20; $i++) { - $menu1[] = $i; + $options[] = $i; } - $mform->addElement('select', 'studentsee', get_string('ordering_itemsforstudent', 'qtype_ordering'), $menu1); + $mform->addElement('select', 'studentsee', get_string('ordering_itemsforstudent', 'qtype_ordering'), $options); $mform->setDefault('studentsee', 0); $repeated = array(); $repeated[] =& $mform->createElement('header', 'choicehdr', get_string('ordering_choiceno', 'qtype_ordering', '{no}')); $repeated[] =& $mform->createElement('textarea', 'answer', get_string('ordering_answer', 'qtype_ordering'), 'rows="3" cols="50"'); - if (isset($this->question->options)){ - $countanswers = count($this->question->options->answers); - } else { + if (empty($this->question->options)){ $countanswers = 0; + } else { + $countanswers = count($this->question->options->answers); + } + if ($NUMANS_START > ($countanswers + $NUMANS_ADD)) { + $repeatsatstart = $NUMANS_START; + } else { + $repeatsatstart = ($countanswers + $NUMANS_ADD); } - $repeatsatstart = ($NUMANS_START > ($countanswers + $NUMANS_ADD))? - $NUMANS_START : ($countanswers + $NUMANS_ADD); $repeatedoptions = array(); $repeatedoptions['fraction']['default'] = 0; $mform->setType('answer', PARAM_NOTAGS); @@ -109,27 +121,16 @@ class qtype_ordering_edit_form extends question_edit_form { } - //echo "data_preprocessing"; - //print_r ($question); - //die(); - return $question; - - //return true; } public function validation($data, $files) { $errors = array(); - $answers = $data['answer']; + $answercount = 0; - - $totalfraction = 0; - $maxfraction = -1; - - foreach ($answers as $key => $answer){ - //check no of choices - $trimmedanswer = trim($answer); - if (!empty($trimmedanswer)){ + foreach ($data['answer'] as $answer){ + $answer = trim($answer); + if ($answer || $answer==='0'){ $answercount++; } } @@ -144,8 +145,4 @@ class qtype_ordering_edit_form extends question_edit_form { return $errors; } - - public function qtype() { - return 'ordering'; - } } diff --git a/question/type/ordering/question.php b/question/type/ordering/question.php index 19f451844ed..05f7366314a 100644 --- a/question/type/ordering/question.php +++ b/question/type/ordering/question.php @@ -15,7 +15,7 @@ // along with Moodle. If not, see . /** - * Multiple choice question definition classes. + * Ordering question definition classes. * * @package qtype * @subpackage ordering @@ -26,16 +26,11 @@ defined('MOODLE_INTERNAL') || die(); /** - * Base class for multiple choice questions. The parts that are common to - * single select and multiple select. + * Represents an ordering question. * * @copyright 2009 The Open University * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -abstract class qtype_ordering_base extends question_graded_automatically { - -} - class qtype_ordering_question extends question_graded_automatically { public $rightanswer; public $truefeedback; @@ -52,140 +47,107 @@ class qtype_ordering_question extends question_graded_automatically { } public function summarise_response(array $response) { - } public function classify_response(array $response) { print_r ($response); - echo "!2!"; + echo 'STOP in question/type/ordering/question.php classify_response()'; die(); - if (!array_key_exists('answer', $response)) { - return array($this->id => question_classified_response::no_response()); - } - list($fraction) = $this->grade_response($response); - if ($response['answer']) { - return array($this->id => new question_classified_response(1, - get_string('true', 'qtype_ordering'), $fraction)); + if (array_key_exists('answer', $response)) { + $responseclassid = ($response['answer'] ? 1 : 0); + list($fraction) = $this->grade_response($response); + return array($this->id => new question_classified_response($responseclassid, get_string('true', 'qtype_ordering'), $fraction)); } else { - return array($this->id => new question_classified_response(0, - get_string('false', 'qtype_ordering'), $fraction)); + return array($this->id => question_classified_response::no_response()); } } public function is_complete_response(array $response) { - global $DB; + global $CFG, $DB; - $answer = $_POST["q".$this->id]; - $orderdata = explode(",", $answer); - $responses = array(); - $erroranswer = array(); + $responses = explode(',', $_POST['q'.$this->id]); + $responses = array_filter($responses); // remove blanks + $responses = array_unique($responses); // remove duplicates - foreach ($orderdata as $orderdata_) { - if (!empty($orderdata_)) - list($a1,$a2,$responses[]) = explode("_", $orderdata_); - } - - //print_r($responses); - - $raw_grade = 0; - - $questionordering = $DB->get_record ("question_ordering", array("question" => $this->id)); - $questionanswers = $DB->get_records ("question_answers", array("question" => $this->id), "id"); - - $fractioncount = 1; - - foreach ($questionanswers as $questionanswersfractiontemp) { - $questionanswers[$questionanswersfractiontemp->id]->fraction = $fractioncount; - ++$fractioncount; - } - - foreach ($questionanswers as $questionanswers_) { - $questionanswersfraction[$questionanswers_->fraction] = $questionanswers_->id; - } - - $erroranswer['main'] = 0; - - if (is_array($responses)) { - if ($questionordering->logical == 0) { - $nefr = 1; - if ($questionordering->studentsee != 0) { - foreach ($questionanswersfraction as $frkey => $frvalue) { - if (in_array($frvalue, $responses)) { - $questionanswersfractionnew [$nefr] = $frvalue; - $nefr ++; - } - } - - $questionanswersfraction = $questionanswersfractionnew; - } - - for ($i = 0; $i <= count($responses) - 1; $i++) { - if ($responses[$i] != $questionanswersfraction[$i + 1]) { - $erroranswer['main'] ++; - } - } - - } else if ($questionordering->logical == 1) { - - $erroranswer['main'] = 0; - for ($i = 0; $i <= count($responses) - 1; $i++) { - if ($i != count($responses) -1) { - if ($questionanswers[$responses[$i]]->fraction > $questionanswers[$responses[$i + 1]]->fraction) { - $erroranswer['main'] ++; - } - } - } - } else if ($questionordering->logical == 2) { - - $fruits = $responses; - - sort($fruits); - reset($fruits); - - if ($responses[0] != $fruits[0]) { - $erroranswer['main'] ++; - } - - for ($i = 0; $i <= count($responses) - 1; $i++) { - if ($i != count($responses) -1) { - if ($questionanswers[$responses[$i]]->fraction < $questionanswers[$responses[$i + 1]]->fraction) { - $raznica = $questionanswers[$responses[$i + 1]]->fraction - $questionanswers[$responses[$i]]->fraction - 1; - if ($raznica >= 1) { - $alreadycount = "false"; - for ($d = 1; $d <= $raznica; $d++) { - if ($alreadycount == "false") { - if (in_array($questionanswersfraction[$questionanswers[$responses[$i]]->fraction + $d] ,$responses)) { - $alreadycount = "true"; - $erroranswer['main'] ++; - } - } - } - } - } else { - $erroranswer['main'] ++; - } - } - } + foreach ($responses as $i => $response) { + if (substr($response, 0, 14)=='ordering_item_') { + $responses[$i] = substr($response, 14); + } else { + unset($responses[$i]); // remove invalid response } + } + if (! $options = $DB->get_record ('question_ordering', array('question' => $this->id))) { + $options = (object)array('logical' => 0); // shouldn't happen !! + } + if (! $answers = $DB->get_records ('question_answers', array('question' => $this->id), 'fraction')) { + $answers = array(); // shouldn't happen !! + } - if ($questionordering->logical == 0 || $questionordering->logical == 2) - $allcount = count($responses); - else - $allcount = count($responses) - 1; - - $grade = ($allcount - $erroranswer['main']) / $allcount; + if ($options->logical==0) { + $total = count($answers); // require all answers } else { - $state->raw_grade = 0; - $state->grade = 0; + $total = $options->studentsee + 2; // a subset of answers + } + + $validresponses = array(); + foreach ($answers as $answerid => $answer) { + + $response = md5($CFG->passwordsaltmain.$answer->answer); + $sortorder = intval($answer->fraction); + + if (in_array($response, $responses)) { + $answers[$answerid]->sortorder = $sortorder; + $answers[$answerid]->response = $response; + $validresponses[] = $response; + } else { + unset($answers[$answerid]); // this answer is not used + } + } + + // convert $answers to sequentially numbered array + $answers = array_values($answers); + + // sort $answers by sortorder (not really necessary) + usort($answers, array($this, 'usort_sortorder')); + + // remove invalid responses + foreach ($responses as $i => $response) { + if (! in_array($response, $validresponses)) { + unset($responses[$i]); + } + } + unset($validresponses); + + $correct = 0; + foreach ($answers as $i => $answer) { + if (isset($responses[$i]) && $answer->response==$responses[$i]) { + $correct++; + } + $i++; + } + + if ($total==0) { + $grade = 0; + } else { + $grade = round($correct / $total, 5); } $_SESSION['SESSION']->quiz_answer['q'.$this->id] = $grade; - return true; } + public function usort_sortorder($a, $b) { + if ($a->sortorder < $b->sortorder) { + return -1; + } + if ($a->sortorder > $b->sortorder) { + return 1; + } + return 0; // equal values + } + public function is_gradable_response(array $response) { return true; } diff --git a/question/type/ordering/questiontype.php b/question/type/ordering/questiontype.php index 274ba375063..617b4e2fbbc 100644 --- a/question/type/ordering/questiontype.php +++ b/question/type/ordering/questiontype.php @@ -34,140 +34,116 @@ if (class_exists('question_type')) { } /** - * The multiple choice question type. + * The ordering question type. * * @copyright 1999 onwards Martin Dougiamas {@link http://moodle.com} * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ class qtype_ordering extends question_type { - /* - public function get_question_options($question) { - global $DB, $OUTPUT; - $question->options = $DB->get_record('question_ordering', - array('question' => $question->id), '*', MUST_EXIST); - parent::get_question_options($question); + + public function is_not_blank($value) { + $value = trim($value); + return ($value || $value==='0'); } - */ public function save_question_options($question) { - global $DB, $OUTPUT; + global $DB; - foreach ($question->answer as $answerkey => $answervalue) { - $question->fraction[] = $answerkey + 1; - } + $result = new stdClass(); - $result = new stdClass; - if (!$oldanswers = $DB->get_records('question_answers', array('question'=>$question->id), 'id ASC')) { - $oldanswers = array(); - } + // remove empty answers + $question->answer = array_filter($question->answer, array($this, 'is_not_blank')); + $question->answer = array_values($question->answer); // make keys sequential - // following hack to check at least two answers exist - $answercount = 0; - foreach ($question->answer as $key=>$dataanswer) { - if ($dataanswer != "") { - $answercount++; - } - } - $answercount += count($oldanswers); - if ($answercount < 2) { // check there are at lest 2 answers for multiple choice - $result->notice = get_string("ordering_notenoughanswers", "qtype_ordering", "2"); + // count how many answers we have + $countanswers = count($question->answer); + + // check at least two answers exist + if ($countanswers < 2) { + $result->notice = get_string('ordering_notenoughanswers', 'qtype_ordering', '2'); return $result; } + $question->feedback = range(1, $countanswers); + + if ($answerids = $DB->get_records('question_answers', array('question' => $question->id), 'id ASC', 'id,question')) { + $answerids = array_keys($answerids); + } else { + $answerids = array(); + } + // Insert all the new answers - $totalfraction = 0; - $maxfraction = -1; + foreach ($question->answer as $i => $text) { + $answer = (object)array( + 'question' => $question->id, + 'fraction' => ($i + 1), // start at 1 + 'answer' => $text, + 'answerformat' => FORMAT_MOODLE, // =0 + 'feedback' => '', + 'feedbackformat' => FORMAT_MOODLE, // =0 + ); - $answers = array(); - - foreach ($question->answer as $key => $dataanswer) { - if ($dataanswer != "") { - if ($answer = array_shift($oldanswers)) { // Existing answer, so reuse it - $answer->answer = $dataanswer; - $answer->fraction = $question->fraction[$key]; - if (!$DB->update_record("question_answers", $answer)) { - $result->error = "Could not update quiz answer! (id=$answer->id)"; - return $result; - } - } else { - unset($answer); - $answer->answer = $dataanswer; - $answer->question = $question->id; - $answer->fraction = number_format($question->fraction[$key], 7); - $answer->feedback = ""; - //echo '
';
-                    //print_r ($answer);
-                    if (!$answer->id = $DB->insert_record("question_answers", $answer)) {
-                        $result->error = "Could not insert quiz answer! ";
-                        return $result;
-                    }
+            if ($answer->id = array_shift($answerids)) {
+                if (! $DB->update_record('question_answers', $answer)) {
+                    $result->error = 'Could not update quiz answer! (id='.$answer->id.')';
+                    return $result;
                 }
-                $answers[] = $answer->id;
-
-                if ($question->fraction[$key] > 0) {                 // Sanity checks
-                    $totalfraction += $question->fraction[$key];
-                }
-                if ($question->fraction[$key] > $maxfraction) {
-                    $maxfraction = $question->fraction[$key];
+            } else {
+                if (! $answer->id = $DB->insert_record('question_answers', $answer)) {
+                    $result->error = 'Could not insert quiz answer! ';
+                    return $result;
                 }
             }
         }
 
-        $update = true;
-        $options = $DB->get_record("question_ordering", array("question" => $question->id));
-        if (!$options) {
-            $update = false;
-            $options = new stdClass;
-            $options->question = $question->id;
+        // create $options for this ordering question
+        $options = (object)array(
+            'question' => $question->id,
+            'logical' => $question->logical,
+            'studentsee' => $question->studentsee,
+            'correctfeedback' => $question->correctfeedback,
+            'incorrectfeedback' => $question->incorrectfeedback,
+            'partiallycorrectfeedback' => $question->partiallycorrectfeedback
+        );
 
-        }
-        $options->logical = $question->logical;
-        $options->studentsee = $question->studentsee;
-        $options->correctfeedback = $question->correctfeedback;
-        $options->partiallycorrectfeedback = $question->partiallycorrectfeedback;
-        $options->incorrectfeedback = $question->incorrectfeedback;
-
-        if ($update) {
-            if (!$DB->update_record("question_ordering", $options)) {
-                $result->error = "Could not update quiz ordering options! (id=$options->id)";
+        // add/update $options for this ordering question
+        if ($options->id = $DB->get_field('question_ordering', 'id', array('question' => $question->id))) {
+            if (! $DB->update_record('question_ordering', $options)) {
+                $result->error = 'Could not update quiz ordering options! (id='.$options->id.')';
                 return $result;
             }
         } else {
-            if (!$DB->insert_record("question_ordering", $options)) {
-                $result->error = "Could not insert quiz ordering options!";
+            if (! $options->id = $DB->insert_record('question_ordering', $options)) {
+                $result->error = 'Could not insert question ordering options!';
                 return $result;
             }
         }
 
-        // delete old answer records
-        if (!empty($oldanswers)) {
-            foreach($oldanswers as $oa) {
-                $DB->delete_records('question_answers', array('id' => $oa->id));
-            }
+        // delete old answer records, if any
+        if (count($answerids)) {
+            $DB->delete_records_list('question_answers', 'id', $answerids);
         }
 
-        /// Perform sanity checks on fractional grades
         return true;
     }
 
     public function get_question_options($question) {
         global $DB, $OUTPUT;
-        // Get additional information from database
-        // and attach it to the question object
-        if (!$question->options = $DB->get_record('question_ordering',
-                array('question' => $question->id))) {
+
+        // load the options
+        if (! $question->options = $DB->get_record('question_ordering', array('question' => $question->id))) {
             echo $OUTPUT->notification('Error: Missing question options!');
             return false;
         }
-        // Load the answers
-        if (!$question->options->answers = $DB->get_records('question_answers',
-                array('question' =>  $question->id), 'id ASC')) {
-            echo $OUTPUT->notification('Error: Missing question answers for truefalse question ' .
-                    $question->id . '!');
+
+        // Load the answers - "fraction" is used to signify the order of the answers
+        if (! $question->options->answers = $DB->get_records('question_answers', array('question' => $question->id), 'fraction ASC')) {
+            echo $OUTPUT->notification('Error: Missing question answers for ordering question ' . $question->id . '!');
             return false;
         }
 
+        //parent::get_question_options($question);
         return true;
     }
 /*
@@ -195,10 +171,8 @@ class qtype_ordering extends question_type {
     public function delete_question($questionid, $contextid) {
         global $DB;
         $DB->delete_records('question_ordering', array('question' => $questionid));
-
         parent::delete_question($questionid, $contextid);
     }
-
 }
 
 // NEW LINES START
diff --git a/question/type/ordering/renderer.php b/question/type/ordering/renderer.php
index b0fcce705a3..626ff51b472 100644
--- a/question/type/ordering/renderer.php
+++ b/question/type/ordering/renderer.php
@@ -34,121 +34,160 @@ defined('MOODLE_INTERNAL') || die();
 class qtype_ordering_renderer extends qtype_renderer {
 
     public function formulation_and_controls(question_attempt $qa, question_display_options $options) {
-        global $DB, $CFG;
+        global $CFG, $DB;
+        static $addStyle = true;
+        static $addScript = true;
 
         $question = $qa->get_question();
 
-        if (! $ordering = $DB->get_record('question_ordering', array('question' => $question->id))) {
+        if (! $options = $DB->get_record('question_ordering', array('question' => $question->id))) {
             return '';
         }
-        if (empty($ordering->studentsee)) {
-            $ordering->studentsee = 100;
-        } else {
-            $ordering->studentsee += 2;
-        }
 
-        if (! $answers = $DB->get_records('question_answers', array('question' => $question->id), '', '*', 0, $ordering->studentsee)) {
+        if (! $answers = $DB->get_records('question_answers', array('question' => $question->id), '', '*')) {
             return ''; // shouldn't happen !!
         }
-        shuffle($answers);
+
+        if ($options->studentsee==0) { // all items
+            $options->studentsee = count($answers);
+        } else {
+            // a nasty hack so that "studentsee" is the same
+            // as what is displayed by edit_ordering_form.php
+            $options->studentsee += 2;
+        }
+
+        switch ($options->logical) {
+
+            case 0: // all
+                $answerids = array_keys($answers);
+                break;
+
+            case 1: // random subset
+                $answerids = array_rand($answers, $options->studentsee);
+                break;
+
+            case 2: // contiguous subset
+                if (count($answers) > $options->studentsee) {
+                    $offset = mt_rand(0, count($answers) - $options->studentsee);
+                    $answers = array_slice($answers, $offset, $options->studentsee, true);
+                }
+                $answerids = array_keys($answers);
+                break;
+        }
+        shuffle($answerids);
 
         $result = '';
-        $result .= html_writer::tag('script', '', array('type'=>'text/javascript', 'src'=>$CFG->wwwroot.'/question/type/ordering/jquery.js'));
-        $result .= html_writer::tag('script', '', array('type'=>'text/javascript', 'src'=>$CFG->wwwroot.'/question/type/ordering/jquery-ui.js'));
+        $result .= html_writer::tag('script', '', array('type'=>'text/javascript', 'src'=>$CFG->wwwroot.'/question/type/ordering/js/jquery.js'));
+        $result .= html_writer::tag('script', '', array('type'=>'text/javascript', 'src'=>$CFG->wwwroot.'/question/type/ordering/js/jquery-ui.js'));
 
         $style = "\n";
-        $style .= "ul.sortable li {\n";
+        $style .= "ul.sortable".$question->id." li {\n";
         $style .= "    position: relative;\n";
         $style .= "}\n";
-        $style .= "ul.boxy {\n";
-        $style .= "    border: 1px solid #ccc;\n";
-        $style .= "    float: left;\n";
-        $style .= "    font-family: Arial, sans-serif;\n";
-        $style .= "    font-size: 13px;\n";
-        $style .= "    list-style-type: none;\n";
-        $style .= "    margin: 0px;\n";
-        $style .= "    margin-left: 5px;\n";
-        $style .= "    padding: 4px 4px 0 4px;\n";
-        $style .= "    width: 360px;\n";
-        $style .= "}\n";
-        $style .= "ul.boxy li {\n";
-        $style .= "    background-color: #eeeeee;\n";
-        $style .= "    border: 1px solid #cccccc;\n";
-        $style .= "    border-image: initial;\n";
-        $style .= "    cursor: move;\n";
-        $style .= "    list-style-type: none;\n";
-        $style .= "    margin-bottom: 1px;\n";
-        $style .= "    min-height: 20px;\n";
-        $style .= "    padding: 8px 2px;\n";
-        $style .= "}\n";
+        if ($addStyle) {
+            $addStyle = false; // only add style once
+            $style .= "ul.boxy {\n";
+            $style .= "    border: 1px solid #ccc;\n";
+            $style .= "    float: left;\n";
+            $style .= "    font-family: Arial, sans-serif;\n";
+            $style .= "    font-size: 13px;\n";
+            $style .= "    list-style-type: none;\n";
+            $style .= "    margin: 0px;\n";
+            $style .= "    margin-left: 5px;\n";
+            $style .= "    padding: 4px 4px 0 4px;\n";
+            $style .= "    width: 360px;\n";
+            $style .= "}\n";
+            $style .= "ul.boxy li {\n";
+            $style .= "    background-color: #eeeeee;\n";
+            $style .= "    border: 1px solid #cccccc;\n";
+            $style .= "    border-image: initial;\n";
+            $style .= "    cursor: move;\n";
+            $style .= "    list-style-type: none;\n";
+            $style .= "    margin-bottom: 1px;\n";
+            $style .= "    min-height: 20px;\n";
+            $style .= "    padding: 8px 2px;\n";
+            $style .= "}\n";
+        }
         $result .= html_writer::tag('style', $style, array('type' => 'text/css'));
 
         $script = "\n";
+        $script .= "//id."').sortable({\n";
         $script .= "        update: function(event, ui) {\n";
         $script .= "            var ItemsOrder = $(this).sortable('toArray').toString();\n";
         $script .= "            $('#q".$question->id."').attr('value', ItemsOrder);\n";
         $script .= "        }\n";
         $script .= "    });\n";
-        $script .= "    $('#sortable').disableSelection();\n";
+        $script .= "    $('#sortable".$question->id."').disableSelection();\n";
         $script .= "});\n";
         $script .= "$(document).ready(function() {\n";
-        $script .= "    var ItemsOrder = $('#sortable').sortable('toArray').toString();\n";
+        $script .= "    var ItemsOrder = $('#sortable".$question->id."').sortable('toArray').toString();\n";
         $script .= "    $('#q".$question->id."').attr('value', ItemsOrder);\n";
         $script .= "});\n";
+        $script .= "//]]>\n";
         $result .= html_writer::tag('script', $script, array('type' => 'text/javascript'));
 
         $result .= html_writer::tag('div', stripslashes($question->format_questiontext($qa)), array('class' => 'qtext'));
         $result .= html_writer::start_tag('div', array('class' => 'ablock'));
         $result .= html_writer::start_tag('div', array('class' => 'answer'));
-        $result .= html_writer::start_tag('ul', array('class' => 'boxy', 'id' => 'sortable'));
+        $result .= html_writer::start_tag('ul', array('class' => 'boxy', 'id' => 'sortable'.$question->id));
 
-        foreach ($answers as $answer) {
-            // $answer->fraction holds the correct order - as a decimal ?!
-            $id = 'ordering_item_'.$answer->id.'_'.intval($answer->fraction);
+        // generate ordering items
+        foreach ($answerids as $i => $answerid) {
+            // the original "id" revealed the correct order of the answers
+            // because $answer->fraction holds the correct order number
+            // $id = 'ordering_item_'.$answerid.'_'.intval($answers[$answerid]->fraction);
+            $id = 'ordering_item_'.md5($CFG->passwordsaltmain.$answers[$answerid]->answer);
             $params = array('class' => 'ui-state-default', 'id' => $id);
-            $result .= html_writer::tag('li', stripslashes($answer->answer), $params);
+            $result .= html_writer::tag('li', $answers[$answerid]->answer, $params);
         }
 
         $result .= html_writer::end_tag('ul');
         $result .= html_writer::end_tag('div'); // answer
         $result .= html_writer::end_tag('div'); // ablock
 
-        $result .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'q'.$question->id, 'id' => 'q'.$question->id));
-        $result .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'answer', 'value' => '712'));
+        $result .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'q'.$question->id, 'id' => 'q'.$question->id, 'value' => '9'));
+        $result .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'answer', 'value' => ''));
 
         $result .= html_writer::tag('div', '', array('style' => 'clear:both;'));
 
         $script = "\n";
-        $script .= "function orderingTouchHandler(event) {\n";
-        $script .= "    var touch = event.changedTouches[0];\n";
-        $script .= "    switch (event.type) {\n";
-        $script .= "        case 'touchstart': var type = 'mousedown'; break;\n";
-        $script .= "        case 'touchmove': var type = 'mousemove'; event.preventDefault(); break;\n";
-        $script .= "        case 'touchend': var type = 'mouseup'; break;\n";
-        $script .= "        default: return;\n";
-        $script .= "    }\n";
-        $script .= "    var simulatedEvent = document.createEvent('MouseEvent');\n";
-        $script .= "    //initMouseEvent(type, canBubble, cancelable, view, clickCount, screenX, screenY, clientX, clientY, ctrlKey, altKey, shiftKey, metaKey, button, relatedTarget);\n";
-        $script .= "    simulatedEvent.initMouseEvent(type, true, true, window, 1, touch.screenX, touch.screenY, touch.clientX, touch.clientY, false, false, false, false, 0/*left*/, null);\n";
-        $script .= "    touch.target.dispatchEvent(simulatedEvent);\n";
-        $script .= "    event.preventDefault();\n";
-        $script .= "}\n";
-        $script .= "function orderingInit() {\n";
-        $script .= "    var obj = document.getElementById('sortable');\n";
-        $script .= "    if (obj) {\n";
-        $script .= "        for (var i=0; iid."');\n";
+        $script .= "//]]>\n";
         $result .= html_writer::tag('script', $script, array('type' => 'text/javascript'));
 
         return $result;