Skip to content

Commit

Permalink
wip feat: check allowshuffle
Browse files Browse the repository at this point in the history
  • Loading branch information
alexanderschmitz committed Mar 18, 2024
1 parent 720d98a commit 61e73df
Show file tree
Hide file tree
Showing 8 changed files with 35 additions and 2 deletions.
1 change: 1 addition & 0 deletions classes/question_service.php
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ public function get_question(int $questionid): object {

$result->qpy_package_hash = $package->hash;
$result->qpy_state = $record->state;
$result->shuffleanswers = $record->shuffleanswers;
}

return $result;
Expand Down
12 changes: 10 additions & 2 deletions classes/question_ui_renderer.php
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,9 @@ class question_ui_renderer {
/** @var question_metadata|null $metadata */
private ?question_metadata $metadata = null;

/** @var boolean Whether the questions answers should be shuffled. */
public bool $shuffleanswers;

/**
* Parses the given XML and initializes a new {@see question_ui_renderer} instance.
*
Expand Down Expand Up @@ -236,6 +239,9 @@ private function render_part(DOMNode $part, question_attempt $qa, question_displ
// Resetting it to its original state would be ideal, but that doesn't seem to be possible.
mt_srand($nextseed);
}
$newdoc->appendChild($newdoc->createElement("test", $this->shuffleanswers));
$newdoc->appendChild($newdoc->createElement("test", get_config('quiz', 'shuffleanswers')));


return $newdoc->saveHTML();
}
Expand Down Expand Up @@ -282,14 +288,16 @@ private function shuffle_contents(\DOMXPath $xpath): void {
$childelements[] = $child;
}
}
shuffle($childelements);
if ($this->shuffleanswers) {
shuffle($childelements);
}

// Iterate over children, replacing elements with random ones while copying everything else.
$i = 1;
while ($element->hasChildNodes()) {
$child = $element->firstChild;
if ($child instanceof DOMElement) {
$child = array_pop($childelements);
$child = array_shift($childelements);
$newelement->appendChild($child);
$this->replace_shuffled_indices($xpath, $child, $i++);
} else {
Expand Down
1 change: 1 addition & 0 deletions db/install.xml
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
<FIELD NAME="feedback" TYPE="text" NOTNULL="true" SEQUENCE="false" COMMENT="Feedback shown for any response."/>
<FIELD NAME="pkgversionid" TYPE="int" LENGTH="10" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="state" TYPE="text" NOTNULL="true" SEQUENCE="false"/>
<FIELD NAME="shuffleanswers" TYPE="int" LENGTH="4" NOTNULL="true" DEFAULT="1" SEQUENCE="false" COMMENT="Whether the content of a qpy:shuffle-contents can be randomly shuffled."/>
</FIELDS>
<KEYS>
<KEY NAME="primary" TYPE="primary" FIELDS="id" />
Expand Down
4 changes: 4 additions & 0 deletions edit_questionpy_form.php
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,10 @@ protected function definition_inner($mform): void {
$mform->addElement('hidden', 'qpy_package_hash', '');
$mform->setType('qpy_package_hash', PARAM_RAW);

// Whether the content of a qpy:shuffle-contents can be randomly shuffled.
$mform->addElement('hidden', 'shuffleanswers', '1');
$mform->setType('shuffleanswers', PARAM_INT);

// While not a button, we need a way of telling moodle not to save the submitted data to the question when the
// package has simply been changed. The hidden element is enabled from JS when a package is selected or changed.
$mform->registerNoSubmitButton('qpy_package_changed');
Expand Down
4 changes: 4 additions & 0 deletions lang/en/qtype_questionpy.php
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,10 @@
$string['server_info_requests_in_process'] = 'Requests in process';
$string['server_info_requests_in_queue'] = 'Requests in queue';

// Question settings
$string['shuffleanswers'] = 'Shuffle the contents?';
$string['shuffleanswers_desc'] = 'Whether the content of a qpy:shuffle-contents should be randomly shuffled for each attempt by default.';

// Package upload.
$string['formerror_noqpy_package'] = 'Selected file must be of type .qpy';

Expand Down
5 changes: 5 additions & 0 deletions question.php
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ class qtype_questionpy_question extends question_graded_automatically_with_count
private string $packagehash;
/** @var string */
private string $questionstate;
/** @var boolean Whether the questions answers should be shuffled. */
public bool $shuffleanswers;

// Properties which do change between attempts (i.e. are modified by start_attempt and apply_attempt_state).
/** @var string */
Expand Down Expand Up @@ -92,6 +94,7 @@ public function start_attempt(question_attempt_step $step, $variant): void {
$this->scoringstate = null;

$this->ui = new question_ui_renderer($attempt->ui->content, $attempt->ui->placeholders);
$this->ui->shuffleanswers = $this->shuffleanswers;
}

/**
Expand Down Expand Up @@ -123,6 +126,7 @@ public function apply_attempt_state(question_attempt_step $step) {
$attempt = $this->api->view_attempt($this->packagehash, $this->questionstate, $this->attemptstate,
$this->scoringstate);
$this->ui = new question_ui_renderer($attempt->ui->content, $attempt->ui->placeholders);
$this->ui->shuffleanswers = $this->shuffleanswers;
}

/**
Expand Down Expand Up @@ -223,6 +227,7 @@ public function grade_response(array $response): array {
$response
);
$this->ui = new question_ui_renderer($attemptscored->ui->content, $attemptscored->ui->placeholders);
$this->ui->shuffleanswers = $this->shuffleanswers;
// TODO: Persist scoring state. We need to set a qtvar, but we don't have access to the pending step here.
$this->scoringstate = $attemptscored->scoringstate;
switch ($attemptscored->scoringcode) {
Expand Down
5 changes: 5 additions & 0 deletions questiontype.php
Original file line number Diff line number Diff line change
Expand Up @@ -145,4 +145,9 @@ public function get_question_options($question): bool {
protected function make_question_instance($questiondata) {
return new qtype_questionpy_question($questiondata->qpy_package_hash, $questiondata->qpy_state);
}

protected function initialise_question_instance(question_definition $question, $questiondata) {
parent::initialise_question_instance($question, $questiondata);
$question->shuffleanswers = $questiondata->shuffleanswers;
}
}
5 changes: 5 additions & 0 deletions settings.php
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@
5
));

// Question settings.
$settings->add(new admin_setting_configcheckbox('qtype_questionpy/shuffleanswers',
new lang_string('shuffleanswers', 'qtype_questionpy'),
new lang_string('shuffleanswers_desc', 'qtype_questionpy'), '1'));

$settings->add(new admin_setting_heading(
'qtype_questionpy/server_info',
new lang_string('server_info_heading', 'qtype_questionpy'),
Expand Down

0 comments on commit 61e73df

Please sign in to comment.