MDL-79863 qtype_ordering: Moodle.2x question/type/ordering use md5 instead of fraction field as id in ordering questions
This commit is contained in:
committed by
Mathew May
parent
2da308c7dd
commit
05a43d9094
@@ -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';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
@@ -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 '<pre>';
|
||||
//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
|
||||
|
||||
@@ -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 .= "//<![CDATA[\n";
|
||||
$script .= "$(function() {\n";
|
||||
$script .= " $('#sortable').sortable({\n";
|
||||
$script .= " $('#sortable".$question->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; i<obj.childNodes.length; i++) {\n";
|
||||
$script .= " obj.childNodes.item(i).addEventListener('touchstart', orderingTouchHandler, false);\n";
|
||||
$script .= " obj.childNodes.item(i).addEventListener('touchmove', orderingTouchHandler, false);\n";
|
||||
$script .= " obj.childNodes.item(i).addEventListener('touchend', orderingTouchHandler, false);\n";
|
||||
$script .= " obj.childNodes.item(i).addEventListener('touchcancel', orderingTouchHandler, false);\n";
|
||||
$script .= " }\n";
|
||||
$script .= " } else {\n";
|
||||
$script .= " setTimeout(orderingInit, 500);\n"; // try again in 1/2 a second
|
||||
$script .= " }\n";
|
||||
$script .= "}\n";
|
||||
$script .= "orderingInit();\n";
|
||||
$script .= "//<![CDATA[\n";
|
||||
if ($addScript) {
|
||||
$addScript = false; // only add these functions once
|
||||
$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, null);\n";
|
||||
$script .= " touch.target.dispatchEvent(simulatedEvent);\n";
|
||||
$script .= " event.preventDefault();\n";
|
||||
$script .= "}\n";
|
||||
$script .= "function orderingInit(sortableid) {\n";
|
||||
$script .= " var obj = document.getElementById(sortableid);\n";
|
||||
$script .= " if (obj) {\n";
|
||||
$script .= " for (var i=0; i<obj.childNodes.length; i++) {\n";
|
||||
$script .= " obj.childNodes.item(i).addEventListener('touchstart', orderingTouchHandler, false);\n";
|
||||
$script .= " obj.childNodes.item(i).addEventListener('touchmove', orderingTouchHandler, false);\n";
|
||||
$script .= " obj.childNodes.item(i).addEventListener('touchend', orderingTouchHandler, false);\n";
|
||||
$script .= " obj.childNodes.item(i).addEventListener('touchcancel', orderingTouchHandler, false);\n";
|
||||
$script .= " }\n";
|
||||
$script .= " obj = null;\n";
|
||||
$script .= " } else {\n";
|
||||
$script .= " // try again in 1/2 a second - shouldn't be necessary !!\n";
|
||||
$script .= " setTimeout(new Function('orderingInit(".'"'."'+sortableid+'".'"'.")'), 500);\n";
|
||||
$script .= " }\n";
|
||||
$script .= "}\n";
|
||||
}
|
||||
$script .= "orderingInit('sortable".$question->id."');\n";
|
||||
$script .= "//]]>\n";
|
||||
$result .= html_writer::tag('script', $script, array('type' => 'text/javascript'));
|
||||
|
||||
return $result;
|
||||
|
||||
Reference in New Issue
Block a user