MDL-79873 qtype_ordering: Template to output formulation and controls.

Part of: MDL-79863
This commit is contained in:
Ilya Tregubov 2023-12-15 09:17:58 +08:00 committed by Mathew May
parent 9d060922ae
commit ec320c2e49
6 changed files with 411 additions and 346 deletions

View file

@ -0,0 +1,135 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace qtype_ordering\output;
use question_attempt;
use question_display_options;
/**
* Renderable class for the displaying the formulation and controls of the question.
*
* @package qtype_ordering
* @copyright 2023 Ilya Tregubov <ilya.a.tregubov@gmail.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
class formulation_and_controls extends renderable_base {
/** @var question_display_options $options The question options. */
protected $options;
/**
* The class constructor.
*
* @param question_attempt $qa The question attempt object.
*/
public function __construct(question_attempt $qa, question_display_options $options) {
$this->options = $options;
parent::__construct($qa);
}
/**
* Export the data for the mustache template.
*
* @param \renderer_base $output renderer to be used to render the action bar elements.
* @return array
*/
public function export_for_template(\renderer_base $output): array {
global $PAGE;
$data = [];
$question = $this->qa->get_question();
$response = $this->qa->get_last_qt_data();
$question->update_current_response($response);
$currentresponse = $question->currentresponse;
$correctresponse = $question->correctresponse;
// Generate fieldnames and ids.
$responsefieldname = $question->get_response_fieldname();
$responsename = $this->qa->get_qt_field_name($responsefieldname);
$data['questiontext'] = $question->format_questiontext($this->qa);
$data['ablockid'] = 'id_ablock_' . $question->id;
$data['sortableid'] = 'id_sortable_' . $question->id;
$data['responsename'] = $responsename;
$data['responseid'] = 'id_' . preg_replace('/[^a-zA-Z0-9]+/', '_', $responsename);
// Set CSS classes for sortable list.
if ($class = $question->get_ordering_layoutclass()) {
$data['layoutclass'] = $class;
}
if ($numberingstyle = $question->options->numberingstyle) {
$data['numberingstyle'] = $numberingstyle;
}
// In the multi-tries, the highlight response base on the hint highlight option.
if ((isset($this->options->highlightresponse) && $this->options->highlightresponse) || !$this->qa->get_state()->is_active()) {
$data['active'] = false;
} else if ($this->qa->get_state()->is_active()) {
$data['active'] = true;
}
$data['readonly'] = $this->options->readonly;
if (count($currentresponse)) {
// Initialize the cache for the answers' md5keys
// this represents the initial position of the items.
$md5keys = [];
// Generate ordering items.
foreach ($currentresponse as $position => $answerid) {
if (!array_key_exists($answerid, $question->answers) || !array_key_exists($position, $correctresponse)) {
continue; // Shouldn't happen !!
}
// Format the answer text.
$answer = $question->answers[$answerid];
$answertext = $question->format_text($answer->answer, $answer->answerformat,
$this->qa, 'question', 'answer', $answerid);
// The original "id" revealed the correct order of the answers
// because $answer->fraction holds the correct order number.
// Therefore, we use the $answer's md5key for the "id".
$answerdata = [
'answertext' => $answertext,
'id' => $answer->md5key,
];
if ($this->options->correctness === question_display_options::VISIBLE ||
!empty($this->options->highlightresponse)) {
$score = $question->get_ordering_item_score($question, $position, $answerid);
if (isset($score['maxscore'])) {
$renderer = $PAGE->get_renderer('qtype_ordering');
$answerdata['feedbackimage'] = $renderer->feedback_image($score['fraction']);
}
$answerdata['scoreclass'] = $score['class'];
}
$data['answers'][] = $answerdata;
// Cache this answer key.
$md5keys[] = $answer->md5key;
}
}
$data['value'] = implode(',', $md5keys);
return $data;
}
}

View file

@ -74,17 +74,16 @@ class specific_grade_detail_feedback extends renderable_base {
foreach ($currentresponse as $position => $answerid) {
if (array_key_exists($answerid, $question->answers)) {
$score = $question->get_ordering_item_score($question, $position, $answerid);
[$score, $maxscore, $fraction, $percent, $class] = $score;
if (!isset($maxscore)) {
$score = get_string('noscore', $plugin);
if (!isset($score['maxscore'])) {
$score['score'] = get_string('noscore', $plugin);
} else {
$totalscore += $score;
$totalmaxscore += $maxscore;
$totalscore += $score['score'];
$totalmaxscore += $score['maxscore'];
}
$data['scoredetails'][] = [
'score' => $score,
'maxscore' => $maxscore,
'percent' => $percent,
'score' => $score['score'],
'maxscore' => $score['maxscore'],
'percent' => $score['percent'],
];
}
}

View file

@ -1065,8 +1065,14 @@ class qtype_ordering_question extends question_graded_automatically {
};
}
$score = [$score, $maxscore, $fraction, $percent, $class];
$this->itemscores[$position] = $score;
$itemscores = [
'score' => $score,
'maxscore' => $maxscore,
'fraction' => $fraction,
'percent' => $percent,
'class' => $class,
];
$this->itemscores[$position] = $itemscores;
}
return $this->itemscores[$position];

View file

@ -55,144 +55,9 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer {
* @return string HTML fragment.
*/
public function formulation_and_controls(question_attempt $qa, question_display_options $options) {
global $CFG, $DB;
// Initialize the return result.
$result = '';
$question = $qa->get_question();
$response = $qa->get_last_qt_data();
$question->update_current_response($response);
$currentresponse = $question->currentresponse;
$correctresponse = $question->correctresponse;
// Generate fieldnames and ids
// response_fieldname : 1_response_319
// response_name : q27:1_response_319
// response_id : id_q27_1_response_319
// sortable_id : id_sortable_q27_1_response_319.
$responsefieldname = $question->get_response_fieldname();
$responsename = $qa->get_qt_field_name($responsefieldname);
$responseid = 'id_'.preg_replace('/[^a-zA-Z0-9]+/', '_', $responsename);
$sortableid = 'id_sortable_'.$question->id;
$ablockid = 'id_ablock_'.$question->id;
// Set CSS classes for sortable list and sortable items.
$sortablelist = 'sortablelist';
if ($class = $question->get_ordering_layoutclass()) {
$sortablelist .= ' '.$class; // Vertical or Horizontal.
}
if ($class = $question->options->numberingstyle) {
$sortablelist .= ' numbering'.$class;
}
if ($qa->get_state()->is_active()) {
$sortablelist .= ' active';
} else {
$sortablelist .= ' notactive';
}
// In the multi-tries, the highlight response base on the hint highlight option.
$hint = null;
if (method_exists($qa->get_behaviour(), 'get_applicable_hint')) {
/** @var \qtype_ordering\question_hint_ordering $hint */
$hint = $qa->get_behaviour()->get_applicable_hint();
}
if ($hint && $hint->highlightresponse) {
$sortablelist .= ' notactive';
}
// Initialise JavaScript if not in readonly mode.
if ($options->readonly) {
// Items cannot be dragged in readonly mode.
$sortableitem = '';
} else {
$sortableitem = 'sortableitem';
$params = array($sortableid, $responseid);
$this->page->requires->js_call_amd('qtype_ordering/drag_reorder', 'init', $params);
}
$result .= html_writer::tag('div', $question->format_questiontext($qa), array('class' => 'qtext'));
$printeditems = false;
if (count($currentresponse)) {
// Initialize the cache for the answers' md5keys
// this represents the initial position of the items.
$md5keys = array();
// Generate ordering items.
foreach ($currentresponse as $position => $answerid) {
if (! array_key_exists($answerid, $question->answers)) {
continue; // Shouldn't happen !!
}
if (! array_key_exists($position, $correctresponse)) {
continue; // Shouldn't happen !!
}
if ($printeditems == false) {
$printeditems = true;
$result .= html_writer::start_tag('div', array('class' => 'ablock', 'id' => $ablockid));
$result .= html_writer::start_tag('div', array('class' => 'answer ordering'));
$result .= html_writer::start_tag('ul', array('class' => $sortablelist, 'id' => $sortableid));
}
// Set the CSS class and correctness img for this response.
// (correctness: HIDDEN=0, VISIBLE=1, EDITABLE=2).
switch ($options->correctness) {
case question_display_options::VISIBLE:
$score = $this->get_ordering_item_score($question, $position, $answerid);
// To do: we need image calculation in MDL-79873.
list($score, $maxscore, $fraction, $percent, $class, $img) = $score;
$class = trim("$sortableitem $class");
break;
case question_display_options::HIDDEN:
case question_display_options::EDITABLE:
$class = $sortableitem;
$img = '';
break;
default:
$class = '';
$img = '';
break;
}
if ($hint && $hint->highlightresponse) {
$score = $this->get_ordering_item_score($question, $position, $answerid);
// To do: we need image calculation here in MDL-79873.
list($score, $maxscore, $fraction, $percent, $class, $img) = $score;
$class = trim("$sortableitem $class");
}
// Format the answer text.
$answer = $question->answers[$answerid];
$answertext = $question->format_text($answer->answer, $answer->answerformat,
$qa, 'question', 'answer', $answerid);
// The original "id" revealed the correct order of the answers
// because $answer->fraction holds the correct order number.
// Therefore we use the $answer's md5key for the "id".
$params = array('class' => $class, 'id' => $answer->md5key);
$result .= html_writer::tag('li', $img.$answertext, $params);
// Cache this answer key.
$md5keys[] = $question->answers[$answerid]->md5key;
}
}
if ($printeditems) {
$result .= html_writer::end_tag('ul');
$result .= html_writer::end_tag('div'); // Close answer tag.
$result .= html_writer::end_tag('div'); // Close ablock tag.
$result .= html_writer::empty_tag('input', array('type' => 'hidden',
'name' => $responsename,
'id' => $responseid,
'value' => implode(',', $md5keys)));
}
return $result;
$formulationandcontrols = new \qtype_ordering\output\formulation_and_controls($qa, $options);
return $this->output->render_from_template('qtype_ordering/formulation_and_controls',
$formulationandcontrols->export_for_template($this->output));
}
/**
@ -252,204 +117,6 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer {
// Custom methods.
/**
* Fills $this->correctinfo and $this->currentinfo depending on question options.
* TO DO: REMOVE ME in MDL-79873
*
* @param object $question
*/
protected function get_response_info($question) {
$gradingtype = $question->options->gradingtype;
switch ($gradingtype) {
case qtype_ordering_question::GRADING_ALL_OR_NOTHING:
case qtype_ordering_question::GRADING_ABSOLUTE_POSITION:
case qtype_ordering_question::GRADING_RELATIVE_TO_CORRECT:
$this->correctinfo = $question->correctresponse;
$this->currentinfo = $question->currentresponse;
break;
case qtype_ordering_question::GRADING_RELATIVE_NEXT_EXCLUDE_LAST:
case qtype_ordering_question::GRADING_RELATIVE_NEXT_INCLUDE_LAST:
$lastitem = ($gradingtype == qtype_ordering_question::GRADING_RELATIVE_NEXT_INCLUDE_LAST);
$this->correctinfo = $question->get_next_answerids($question->correctresponse, $lastitem);
$this->currentinfo = $question->get_next_answerids($question->currentresponse, $lastitem);
break;
case qtype_ordering_question::GRADING_RELATIVE_ONE_PREVIOUS_AND_NEXT:
case qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT:
$all = ($gradingtype == qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT);
$this->correctinfo = $question->get_previous_and_next_answerids($question->correctresponse, $all);
$this->currentinfo = $question->get_previous_and_next_answerids($question->currentresponse, $all);
break;
case qtype_ordering_question::GRADING_LONGEST_ORDERED_SUBSET:
case qtype_ordering_question::GRADING_LONGEST_CONTIGUOUS_SUBSET:
$this->correctinfo = $question->correctresponse;
$this->currentinfo = $question->currentresponse;
$contiguous = ($gradingtype == qtype_ordering_question::GRADING_LONGEST_CONTIGUOUS_SUBSET);
$subset = $question->get_ordered_subset($contiguous);
foreach ($this->currentinfo as $position => $answerid) {
if (array_search($position, $subset) === false) {
$this->currentinfo[$position] = 0;
} else {
$this->currentinfo[$position] = 1;
}
}
break;
}
}
/**
* Returns score for one item depending on correctness and question settings.
*
* TO DO: REMOVE ME in MDL-79873
*
* @param object $question
* @param int $position
* @param int $answerid
* @return array (score, maxscore, fraction, percent, class, img)
*/
protected function get_ordering_item_score($question, $position, $answerid) {
if (! isset($this->itemscores[$position])) {
if ($this->correctinfo === null || $this->currentinfo === null) {
$this->get_response_info($question);
}
$correctinfo = $this->correctinfo;
$currentinfo = $this->currentinfo;
$score = 0; // Actual score for this item.
$maxscore = null; // Max score for this item.
$fraction = 0.0; // Fraction $score / $maxscore.
$percent = 0; // 100 * $fraction.
$class = ''; // CSS class.
$img = ''; // Icon to show correctness.
switch ($question->options->gradingtype) {
case qtype_ordering_question::GRADING_ALL_OR_NOTHING:
if ($this->is_all_correct()) {
$score = 1;
$maxscore = 1;
}
break;
case qtype_ordering_question::GRADING_ABSOLUTE_POSITION:
if (isset($correctinfo[$position])) {
if ($correctinfo[$position] == $answerid) {
$score = 1;
}
$maxscore = 1;
}
break;
case qtype_ordering_question::GRADING_RELATIVE_NEXT_EXCLUDE_LAST:
case qtype_ordering_question::GRADING_RELATIVE_NEXT_INCLUDE_LAST:
if (isset($correctinfo[$answerid])) {
if (isset($currentinfo[$answerid]) && $currentinfo[$answerid] == $correctinfo[$answerid]) {
$score = 1;
}
$maxscore = 1;
}
break;
case qtype_ordering_question::GRADING_RELATIVE_ONE_PREVIOUS_AND_NEXT:
case qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT:
if (isset($correctinfo[$answerid])) {
$maxscore = 0;
$prev = $correctinfo[$answerid]->prev;
$maxscore += count($prev);
$prev = array_intersect($prev, $currentinfo[$answerid]->prev);
$score += count($prev);
$next = $correctinfo[$answerid]->next;
$maxscore += count($next);
$next = array_intersect($next, $currentinfo[$answerid]->next);
$score += count($next);
}
break;
case qtype_ordering_question::GRADING_LONGEST_ORDERED_SUBSET:
case qtype_ordering_question::GRADING_LONGEST_CONTIGUOUS_SUBSET:
if (isset($correctinfo[$position])) {
if (isset($currentinfo[$position])) {
$score = $currentinfo[$position];
}
$maxscore = 1;
}
break;
case qtype_ordering_question::GRADING_RELATIVE_TO_CORRECT:
if (isset($correctinfo[$position])) {
$maxscore = (count($correctinfo) - 1);
$answerid = $currentinfo[$position];
$correctposition = array_search($answerid, $correctinfo);
$score = ($maxscore - abs($correctposition - $position));
if ($score < 0) {
$score = 0;
}
}
break;
}
if ($maxscore === null) {
// An unscored item is either an illegal item
// or last item of RELATIVE_NEXT_EXCLUDE_LAST
// or an item in an incorrect ALL_OR_NOTHING
// or an item from an unrecognized grading type.
$class = 'unscored';
} else {
if ($maxscore == 0) {
$fraction = 0.0;
$percent = 0;
} else {
$fraction = ($score / $maxscore);
$percent = round(100 * $fraction, 0);
}
switch (true) {
case ($fraction > 0.999999):
$class = 'correct';
break;
case ($fraction < 0.000001):
$class = 'incorrect';
break;
case ($fraction >= 0.66):
$class = 'partial66';
break;
case ($fraction >= 0.33):
$class = 'partial33';
break;
default:
$class = 'partial00';
break;
}
$img = $this->feedback_image($fraction);
}
$score = array($score, $maxscore, $fraction, $percent, $class, $img);
$this->itemscores[$position] = $score;
}
return $this->itemscores[$position];
}
/**
* Return true if answer is 100% correct.
* TO DO: REMOVE ME in MDL-79873
*
* @return bool
*/
protected function is_all_correct() {
if ($this->allcorrect === null) {
// Use "==" to determine if the two "info" arrays are identical.
$this->allcorrect = ($this->correctinfo == $this->currentinfo);
}
return $this->allcorrect;
}
/**
* Generate a brief statement of how many sub-parts of this question the
* student got correct|partial|incorrect.
@ -462,4 +129,15 @@ class qtype_ordering_renderer extends qtype_with_combined_feedback_renderer {
return $this->output->render_from_template('qtype_ordering/num_parts_correct',
$numpartscorrect->export_for_template($this->output));
}
/**
* Return an appropriate icon (green tick, red cross, etc.) for a grade.
*
* @param float $fraction grade on a scale 0..1.
* @param bool $selected whether to show a big or small icon. (Deprecated)
* @return string html fragment.
*/
public function feedback_image($fraction, $selected = true): string {
return parent::feedback_image($fraction);
}
}

View file

@ -0,0 +1,86 @@
{{!
This file is part of Moodle - http://moodle.org/
Moodle is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Moodle is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Moodle. If not, see <http://www.gnu.org/licenses/>.
}}
{{!
@template qtype_ordering/formulation_and_controls
Renders the question formulation and controls.
Context variables required for this template:
* questiontext - Question text.
* responsename - Response name for this question attempt.
* responseid - Response name for this question attempt.
* value - Comma separated md5keys of the answer.
* ablockid - Block id.
* layoutclass - Layout class.
* numberingstyle - Numbering style.
* active - if qa is active.
* sortableid - Sortable id.
* answers - An array containing the score details.
* readonly - Whether the question is readonly or not.
Example context (json):
{
"questiontext": "Order this",
"responsename": "q13:1_response_2",
"responseid": "id_q13_1_response_2",
"value": "ordering_item_497031794414a552435f90151ac3b54b,ordering_item_5a35edab0f2bf86dfa3901baa8c235dc",
"ablockid": "id_ablock_2",
"layoutclass": "vertical",
"numberingstyle": "numberingnone",
"active": true,
"sortableid": "id_sortable_2",
"readonly": true,
"answers": [
{
"id": "ordering_item_497031794414a552435f90151ac3b54b",
"scoreclass": "correct",
"answertext": "Oriented",
"feedbackimage": "<i class="icon fa fa-remove text-danger fa-fw" title="Incorrect" role="img" aria-label="Incorrect"></i>"
},
{
"id": "ordering_item_5a35edab0f2bf86dfa3901baa8c235dc",
"scoreclass": "correct",
"answertext": "Object",
"feedbackimage": "<i class="icon fa fa-remove text-danger fa-fw" title="Incorrect" role="img" aria-label="Incorrect"></i>"
}
]
}
}}
<div class="qtext">
{{{questiontext}}}
{{#responsename}}
<div class="ablock" id="{{ablockid}}">
<div class="answer ordering">
<ul class="sortablelist {{layoutclass}} {{#numberingstyle}}numbering{{numberingstyle}}{{/numberingstyle}} {{#active}}active{{/active}}{{^active}}notactive{{/active}}" id="{{sortableid}}">
{{#answers}}
<li class="{{^readonly}}sortableitem{{/readonly}} {{scoreclass}}" id="{{id}}">
{{{feedbackimage}}}{{{answertext}}}
</li>
{{/answers}}
</ul>
</div>
</div>
<input name="{{responsename}}" id="{{responseid}}" type="hidden" value="{{value}}"/>
{{/responsename}}
</div>
{{^readonly}}
{{#js}}
require(['qtype_ordering/drag_reorder'], function(drag_reorder) {
drag_reorder.init('{{sortableid}}', '{{responseid}}');
});
{{/js}}
{{/readonly}}

View file

@ -0,0 +1,161 @@
<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
namespace qtype_ordering\output;
use advanced_testcase;
use question_display_options;
use test_question_maker;
use qtype_ordering_question;
use qtype_ordering_test_helper;
defined('MOODLE_INTERNAL') || die();
global $CFG;
require_once($CFG->dirroot . '/question/engine/tests/helpers.php');
/**
* A test class used to test formulation_and_controls.
*
* @package qtype_ordering
* @copyright 2023 Ilya Tregubov <ilya.a.tregubov@gmail.com.com>
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
* @covers \qtype_ordering\output\specific_grade_detail_feedback
*/
class formulation_and_controls_test extends advanced_testcase {
/**
* Test the exported data for the template that renders the formulation and controls for a given question.
*
* @dataProvider export_for_template_provider
* @param array $answeritems The array of ordered answers.
* @param int $gradingtype Grading type.
* @param string $layouttype The type of the layout.
* @param array $expected The expected exported data.
* @return void
* @covers ::export_for_template
*/
public function test_export_for_template(array $answeritems, int $gradingtype, string $layouttype, array $expected): void {
global $PAGE;
$question = test_question_maker::make_question('ordering');
$question->options->layouttype = $layouttype === 'horizontal' ? qtype_ordering_question::LAYOUT_HORIZONTAL :
qtype_ordering_question::LAYOUT_VERTICAL;
$qa = new \testable_question_attempt($question, 0);
$step = new \question_attempt_step();
$qa->add_step($step);
$question->start_attempt($step, 1);
$options = new question_display_options();
$options->feedback = question_display_options::VISIBLE;
$options->numpartscorrect = question_display_options::VISIBLE;
$options->generalfeedback = question_display_options::VISIBLE;
$options->rightanswer = question_display_options::VISIBLE;
$options->manualcomment = question_display_options::VISIBLE;
$options->history = question_display_options::VISIBLE;
$question->options->gradingtype = $gradingtype;
$keys = implode(',', array_keys($answeritems));
$values = array_values($answeritems);
$step->set_qt_var('_currentresponse', $keys);
[$fraction, $state] = $question->grade_response(qtype_ordering_test_helper::get_response($question, $values));
$qa->get_last_step()->set_state($state);
$renderer = $PAGE->get_renderer('core');
$formulationandcontrols = new formulation_and_controls($qa, $options);
$actual = $formulationandcontrols->export_for_template($renderer);
$this->assertEquals($expected, $actual);
}
/**
* Data provider for the test_export_for_template test.
*
* @return array
*/
public function export_for_template_provider(): array {
global $CFG;
require_once($CFG->dirroot . '/question/type/ordering/question.php');
$success = "<i class=\"icon fa fa-check text-success fa-fw \" title=\"Correct\" role=\"img\" aria-label=\"Correct\"></i>";
$warning = "<i class=\"icon fa fa-check-square fa-fw \" title=\"Partially correct\" role=\"img\" aria-label=\"Partially correct\"></i>";
$error = "<i class=\"icon fa fa-remove text-danger fa-fw \" title=\"Incorrect\" role=\"img\" aria-label=\"Incorrect\"></i>";
return [
'Horizontal, correct and partially correct' => [
[13 => 'Modular', 14 => 'Object', 15 => 'Oriented', 17 => 'Learning', 16 => 'Dynamic', 18 => 'Environment'],
qtype_ordering_question::GRADING_RELATIVE_ALL_PREVIOUS_AND_NEXT,
'horizontal',
[
'readonly' => false,
'questiontext' => 'Put these words in order',
'responsename' => 'q0:_response_0',
'responseid' => 'id_q0_response_0',
'value' => 'ordering_item_ac5fc041de63c8c5b34d0aabb96cf33d,' .
'ordering_item_497031794414a552435f90151ac3b54b,' .
'ordering_item_5a35edab0f2bf86dfa3901baa8c235dc,' .
'ordering_item_8af0f5c3edad8d8e158ff27b9f03afac,' .
'ordering_item_971fd8cc345d8bd9f92e9f7d88fdf20c,' .
'ordering_item_0ba29c6a1afacf586b03a26162c72274',
'ablockid' => 'id_ablock_0',
'layoutclass' => 'horizontal',
'numberingstyle' => 'none',
'active' => false,
'sortableid' => 'id_sortable_0',
'answers' => [
['scoreclass' => 'correct', 'id' => 'ordering_item_' . md5('Modular'), 'answertext' => "Modular", 'feedbackimage' => $success],
['scoreclass' => 'correct', 'id' => 'ordering_item_' . md5('Object'), 'answertext' => "Object", 'feedbackimage' => $success],
['scoreclass' => 'correct', 'id' => 'ordering_item_' . md5('Oriented'), 'answertext' => "Oriented", 'feedbackimage' => $success],
['scoreclass' => 'partial66', 'id' => 'ordering_item_' . md5('Learning'), 'answertext' => "Learning", 'feedbackimage' => $warning],
['scoreclass' => 'partial66', 'id' => 'ordering_item_' . md5('Dynamic'), 'answertext' => "Dynamic", 'feedbackimage' => $warning],
['scoreclass' => 'correct', 'id' => 'ordering_item_' . md5('Environment'), 'answertext' => "Environment", 'feedbackimage' => $success],
],
],
],
'Vertical, incorrect' => [
[14 => 'Object', 16 => 'Dynamic', 13 => 'Modular', 17 => 'Learning', 18 => 'Environment', 15 => 'Oriented'],
qtype_ordering_question::GRADING_ABSOLUTE_POSITION,
'vertical',
[
'readonly' => false,
'questiontext' => 'Put these words in order',
'responsename' => 'q0:_response_0',
'responseid' => 'id_q0_response_0',
'value' => 'ordering_item_497031794414a552435f90151ac3b54b,' .
'ordering_item_971fd8cc345d8bd9f92e9f7d88fdf20c,' .
'ordering_item_ac5fc041de63c8c5b34d0aabb96cf33d,' .
'ordering_item_8af0f5c3edad8d8e158ff27b9f03afac,' .
'ordering_item_0ba29c6a1afacf586b03a26162c72274,' .
'ordering_item_5a35edab0f2bf86dfa3901baa8c235dc',
'ablockid' => 'id_ablock_0',
'layoutclass' => 'vertical',
'numberingstyle' => 'none',
'active' => false,
'sortableid' => 'id_sortable_0',
'answers' => [
['scoreclass' => 'incorrect', 'id' => 'ordering_item_' . md5('Object'), 'answertext' => "Object", 'feedbackimage' => $error],
['scoreclass' => 'incorrect', 'id' => 'ordering_item_' . md5('Dynamic'), 'answertext' => "Dynamic", 'feedbackimage' => $error],
['scoreclass' => 'incorrect', 'id' => 'ordering_item_' . md5('Modular'), 'answertext' => "Modular", 'feedbackimage' => $error],
['scoreclass' => 'incorrect', 'id' => 'ordering_item_' . md5('Learning'), 'answertext' => "Learning", 'feedbackimage' => $error],
['scoreclass' => 'incorrect', 'id' => 'ordering_item_' . md5('Environment'), 'answertext' => "Environment", 'feedbackimage' => $error],
['scoreclass' => 'incorrect', 'id' => 'ordering_item_' . md5('Oriented'), 'answertext' => "Oriented", 'feedbackimage' => $error],
],
],
],
];
}
}