emergency release 2.2dev
[moodle.git] / question / preview.php
CommitLineData
aeb15530 1<?php
c76145d3
TH
2// This file is part of Moodle - http://moodle.org/
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
516cf3eb 17/**
4323d029 18 * This page displays a preview of a question
19 *
20 * The preview uses the option settings from the activity within which the question
21 * is previewed or the default settings if no activity is specified. The question session
22 * information is stored in the session as an array of subsequent states rather
23 * than in the database.
24 *
017bc1d9 25 * @package moodlecore
7764183a 26 * @subpackage questionengine
017bc1d9 27 * @copyright Alex Smith {@link http://maths.york.ac.uk/serving_maths} and
c76145d3 28 * numerous contributors.
7764183a 29 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
4323d029 30 */
516cf3eb 31
017bc1d9 32
c76145d3
TH
33require_once(dirname(__FILE__) . '/../config.php');
34require_once($CFG->libdir . '/questionlib.php');
c76145d3
TH
35require_once(dirname(__FILE__) . '/previewlib.php');
36
76e6cf5d
JP
37/**
38 * The maximum number of variants previewable. If there are more variants than this for a question
39 * then we only allow the selection of the first x variants.
40 * @var integer
41 */
42define('QUESTION_PREVIEW_MAX_VARIANTS', 100);
43
c76145d3
TH
44// Get and validate question id.
45$id = required_param('id', PARAM_INT);
46$question = question_bank::load_question($id);
56a4ae46
TH
47
48// Were we given a particular context to run the question in?
49// This affects things like filter settings, or forced theme or language.
50if ($cmid = optional_param('cmid', 0, PARAM_INT)) {
51 $cm = get_coursemodule_from_id(false, $cmid);
52 require_login($cm->course, false, $cm);
53 $context = get_context_instance(CONTEXT_MODULE, $cmid);
54
55} else if ($courseid = optional_param('courseid', 0, PARAM_INT)) {
56 require_login($courseid);
57 $context = get_context_instance(CONTEXT_COURSE, $courseid);
58
59} else {
60 require_login();
61 $category = $DB->get_record('question_categories',
62 array('id' => $question->category), '*', MUST_EXIST);
63 $context = get_context_instance_by_id($category->contextid);
64 $PAGE->set_context($context);
65 // Note that in the other cases, require_login will set the correct page context.
66}
67question_require_capability_on($question, 'use');
56920c36 68$PAGE->set_pagelayout('popup');
c76145d3
TH
69
70// Get and validate display options.
76e6cf5d 71$maxvariant = min($question->get_num_variants(), QUESTION_PREVIEW_MAX_VARIANTS);
c76145d3
TH
72$options = new question_preview_options($question);
73$options->load_user_defaults();
74$options->set_from_request();
56a4ae46
TH
75$PAGE->set_url(question_preview_url($id, $options->behaviour, $options->maxmark,
76 $options, $options->variant, $context));
c76145d3
TH
77
78// Get and validate exitsing preview, or start a new one.
612106b3
TH
79$previewid = optional_param('previewid', 0, PARAM_INT);
80
c76145d3
TH
81if ($previewid) {
82 if (!isset($SESSION->question_previews[$previewid])) {
83 print_error('notyourpreview', 'question');
84 }
85 try {
86 $quba = question_engine::load_questions_usage_by_activity($previewid);
c014b989 87 } catch (Exception $e) {
c76145d3
TH
88 print_error('submissionoutofsequencefriendlymessage', 'question',
89 question_preview_url($question->id, $options->behaviour,
56a4ae46 90 $options->maxmark, $options, $options->variant, $context), null, $e);
c76145d3
TH
91 }
92 $slot = $quba->get_first_question_number();
93 $usedquestion = $quba->get_question($slot);
94 if ($usedquestion->id != $question->id) {
95 print_error('questionidmismatch', 'question');
96 }
97 $question = $usedquestion;
c014b989 98 $options->variant = $quba->get_variant($slot);
c76145d3
TH
99
100} else {
56a4ae46
TH
101 $quba = question_engine::make_questions_usage_by_activity(
102 'core_question_preview', $context);
c76145d3
TH
103 $quba->set_preferred_behaviour($options->behaviour);
104 $slot = $quba->add_question($question, $options->maxmark);
c014b989
TH
105
106 if ($options->variant) {
107 $options->variant = min($maxvariant, max(1, $options->variant));
108 } else {
109 $options->variant = rand(1, $maxvariant);
110 }
111
112 $quba->start_question($slot, $options->variant);
c76145d3
TH
113
114 $transaction = $DB->start_delegated_transaction();
115 question_engine::save_questions_usage_by_activity($quba);
116 $transaction->allow_commit();
117
118 $SESSION->question_previews[$quba->get_id()] = true;
119}
120$options->behaviour = $quba->get_preferred_behaviour();
121$options->maxmark = $quba->get_question_max_mark($slot);
122
123// Create the settings form, and initialise the fields.
56a4ae46
TH
124$optionsform = new preview_options_form(question_preview_form_url($question->id, $context),
125 array('quba' => $quba, 'maxvariant' => $maxvariant));
c76145d3
TH
126$optionsform->set_data($options);
127
128// Process change of settings, if that was requested.
129if ($newoptions = $optionsform->get_submitted_data()) {
130 // Set user preferences
131 $options->save_user_preview_options($newoptions);
612106b3
TH
132 if (!isset($newoptions->variant)) {
133 $newoptions->variant = $options->variant;
134 }
56a4ae46 135 restart_preview($previewid, $question->id, $newoptions, $context);
c76145d3
TH
136}
137
138// Prepare a URL that is used in various places.
56a4ae46 139$actionurl = question_preview_action_url($question->id, $quba->get_id(), $options, $context);
c76145d3
TH
140
141// Process any actions from the buttons at the bottom of the form.
142if (data_submitted() && confirm_sesskey()) {
143 if (optional_param('restart', false, PARAM_BOOL)) {
56a4ae46 144 restart_preview($previewid, $question->id, $options, $context);
c76145d3
TH
145
146 } else if (optional_param('fill', null, PARAM_BOOL)) {
147 $correctresponse = $quba->get_correct_response($slot);
148 $quba->process_action($slot, $correctresponse);
149
150 $transaction = $DB->start_delegated_transaction();
151 question_engine::save_questions_usage_by_activity($quba);
152 $transaction->allow_commit();
153
154 redirect($actionurl);
155
156 } else if (optional_param('finish', null, PARAM_BOOL)) {
157 try {
158 $quba->process_all_actions();
c014b989 159 } catch (question_out_of_sequence_exception $e) {
c76145d3
TH
160 print_error('submissionoutofsequencefriendlymessage', 'question', $actionurl);
161 }
162 $quba->finish_all_questions();
516cf3eb 163
c76145d3
TH
164 $transaction = $DB->start_delegated_transaction();
165 question_engine::save_questions_usage_by_activity($quba);
166 $transaction->allow_commit();
167 redirect($actionurl);
516cf3eb 168
516cf3eb 169 } else {
c76145d3
TH
170 try {
171 $quba->process_all_actions();
c014b989 172 } catch (question_out_of_sequence_exception $e) {
c76145d3 173 print_error('submissionoutofsequencefriendlymessage', 'question', $actionurl);
516cf3eb 174 }
516cf3eb 175
c76145d3
TH
176 $transaction = $DB->start_delegated_transaction();
177 question_engine::save_questions_usage_by_activity($quba);
178 $transaction->allow_commit();
516cf3eb 179
c76145d3
TH
180 $scrollpos = optional_param('scrollpos', '', PARAM_RAW);
181 if ($scrollpos !== '') {
612106b3 182 $actionurl->param('scrollpos', (int) $scrollpos);
c76145d3
TH
183 }
184 redirect($actionurl);
185 }
186}
187
188if ($question->length) {
189 $displaynumber = '1';
190} else {
191 $displaynumber = 'i';
192}
193$restartdisabled = '';
194$finishdisabled = '';
195$filldisabled = '';
196if ($quba->get_question_state($slot)->is_finished()) {
197 $finishdisabled = ' disabled="disabled"';
198 $filldisabled = ' disabled="disabled"';
199}
200if (!$previewid) {
201 $restartdisabled = ' disabled="disabled"';
202}
203
c76145d3
TH
204// Output
205$title = get_string('previewquestion', 'question', format_string($question->name));
206$headtags = question_engine::initialise_js() . $quba->render_question_head_html($slot);
207$PAGE->set_title($title);
208$PAGE->set_heading($title);
209echo $OUTPUT->header();
210
211// Start the question form.
612106b3 212echo '<form method="post" action="' . $actionurl .
c76145d3
TH
213 '" enctype="multipart/form-data" id="responseform">', "\n";
214echo '<input type="hidden" name="sesskey" value="' . sesskey() . '" />', "\n";
215echo '<input type="hidden" name="slots" value="' . $slot . '" />', "\n";
216
217// Output the question.
218echo $quba->render_question($slot, $options, $displaynumber);
219
220echo '<p class="notifytiny">' . get_string('behaviourbeingused', 'question',
221 question_engine::get_behaviour_name(
222 $quba->get_question_attempt($slot)->get_behaviour_name())) . '</p>';
223// Finish the question form.
224echo '<div id="previewcontrols" class="controls">';
225echo '<input type="submit" name="restart"' . $restartdisabled .
226 ' value="' . get_string('restart', 'question') . '" />', "\n";
227echo '<input type="submit" name="fill"' . $filldisabled .
228 ' value="' . get_string('fillincorrect', 'question') . '" />', "\n";
229echo '<input type="submit" name="finish"' . $finishdisabled .
230 ' value="' . get_string('submitandfinish', 'question') . '" />', "\n";
231echo '<input type="hidden" name="scrollpos" id="scrollpos" value="" />';
232echo '</div>';
233echo '</form>';
234
235// Display the settings form.
236$optionsform->display();
237
cce1b655
TH
238$PAGE->requires->js_init_call('M.core_question_preview.init', null, false, array(
239 'name' => 'core_question_preview',
240 'fullpath' => '/question/preview.js',
241 'requires' => array('base', 'dom', 'event-delegate', 'event-key', 'core_question_engine'),
242 'strings' => array(
243 array('closepreview', 'question'),
244 )));
c76145d3 245echo $OUTPUT->footer();
aeb15530 246