Merged branch 'MDL-27692_master' of git://github.com/MaryE/moodle.git
[moodle.git] / question / preview.php
1 <?php
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/>.
17 /**
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  *
25  * @package    moodlecore
26  * @subpackage questionengine
27  * @copyright  Alex Smith {@link http://maths.york.ac.uk/serving_maths} and
28  *      numerous contributors.
29  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
30  */
33 require_once(dirname(__FILE__) . '/../config.php');
34 require_once($CFG->libdir . '/questionlib.php');
35 require_once(dirname(__FILE__) . '/previewlib.php');
37 // Get and validate question id.
38 $id = required_param('id', PARAM_INT);
39 $question = question_bank::load_question($id);
40 require_login();
41 $category = $DB->get_record('question_categories',
42         array('id' => $question->category), '*', MUST_EXIST);
43 question_require_capability_on($question, 'use');
44 $PAGE->set_pagelayout('popup');
45 $PAGE->set_context(get_context_instance_by_id($category->contextid));
47 // Get and validate display options.
48 $maxvariant = $question->get_num_variants();
49 $options = new question_preview_options($question);
50 $options->load_user_defaults();
51 $options->set_from_request();
52 $PAGE->set_url(question_preview_url($id, $options->behaviour, $options->maxmark, $options));
54 // Get and validate exitsing preview, or start a new one.
55 $previewid = optional_param('previewid', 0, PARAM_INT);
57 if ($previewid) {
58     if (!isset($SESSION->question_previews[$previewid])) {
59         print_error('notyourpreview', 'question');
60     }
61     try {
62         $quba = question_engine::load_questions_usage_by_activity($previewid);
63     } catch (Exception $e) {
64         print_error('submissionoutofsequencefriendlymessage', 'question',
65                 question_preview_url($question->id, $options->behaviour,
66                 $options->maxmark, $options), null, $e);
67     }
68     $slot = $quba->get_first_question_number();
69     $usedquestion = $quba->get_question($slot);
70     if ($usedquestion->id != $question->id) {
71         print_error('questionidmismatch', 'question');
72     }
73     $question = $usedquestion;
74     $options->variant = $quba->get_variant($slot);
76 } else {
77     $quba = question_engine::make_questions_usage_by_activity('core_question_preview',
78             get_context_instance_by_id($category->contextid));
79     $quba->set_preferred_behaviour($options->behaviour);
80     $slot = $quba->add_question($question, $options->maxmark);
82     if ($options->variant) {
83         $options->variant = min($maxvariant, max(1, $options->variant));
84     } else {
85         $options->variant = rand(1, $maxvariant);
86     }
88     $quba->start_question($slot, $options->variant);
90     $transaction = $DB->start_delegated_transaction();
91     question_engine::save_questions_usage_by_activity($quba);
92     $transaction->allow_commit();
94     $SESSION->question_previews[$quba->get_id()] = true;
95 }
96 $options->behaviour = $quba->get_preferred_behaviour();
97 $options->maxmark = $quba->get_question_max_mark($slot);
99 // Create the settings form, and initialise the fields.
100 $optionsform = new preview_options_form(new moodle_url('/question/preview.php',
101         array('id' => $question->id)), array('quba' => $quba, 'maxvariant' => $maxvariant));
102 $optionsform->set_data($options);
104 // Process change of settings, if that was requested.
105 if ($newoptions = $optionsform->get_submitted_data()) {
106     // Set user preferences
107     $options->save_user_preview_options($newoptions);
108     if (!isset($newoptions->variant)) {
109         $newoptions->variant = $options->variant;
110     }
111     restart_preview($previewid, $question->id, $newoptions);
114 // Prepare a URL that is used in various places.
115 $actionurl = question_preview_action_url($question->id, $quba->get_id(), $options);
117 // Process any actions from the buttons at the bottom of the form.
118 if (data_submitted() && confirm_sesskey()) {
119     if (optional_param('restart', false, PARAM_BOOL)) {
120         restart_preview($previewid, $question->id, $options);
122     } else if (optional_param('fill', null, PARAM_BOOL)) {
123         $correctresponse = $quba->get_correct_response($slot);
124         $quba->process_action($slot, $correctresponse);
126         $transaction = $DB->start_delegated_transaction();
127         question_engine::save_questions_usage_by_activity($quba);
128         $transaction->allow_commit();
130         redirect($actionurl);
132     } else if (optional_param('finish', null, PARAM_BOOL)) {
133         try {
134             $quba->process_all_actions();
135         } catch (question_out_of_sequence_exception $e) {
136             print_error('submissionoutofsequencefriendlymessage', 'question', $actionurl);
137         }
138         $quba->finish_all_questions();
140         $transaction = $DB->start_delegated_transaction();
141         question_engine::save_questions_usage_by_activity($quba);
142         $transaction->allow_commit();
143         redirect($actionurl);
145     } else {
146         try {
147             $quba->process_all_actions();
148         } catch (question_out_of_sequence_exception $e) {
149             print_error('submissionoutofsequencefriendlymessage', 'question', $actionurl);
150         }
152         $transaction = $DB->start_delegated_transaction();
153         question_engine::save_questions_usage_by_activity($quba);
154         $transaction->allow_commit();
156         $scrollpos = optional_param('scrollpos', '', PARAM_RAW);
157         if ($scrollpos !== '') {
158             $actionurl->param('scrollpos', (int) $scrollpos);
159         }
160         redirect($actionurl);
161     }
164 if ($question->length) {
165     $displaynumber = '1';
166 } else {
167     $displaynumber = 'i';
169 $restartdisabled = '';
170 $finishdisabled = '';
171 $filldisabled = '';
172 if ($quba->get_question_state($slot)->is_finished()) {
173     $finishdisabled = ' disabled="disabled"';
174     $filldisabled = ' disabled="disabled"';
176 if (!$previewid) {
177     $restartdisabled = ' disabled="disabled"';
180 // Output
181 $title = get_string('previewquestion', 'question', format_string($question->name));
182 $headtags = question_engine::initialise_js() . $quba->render_question_head_html($slot);
183 $PAGE->set_title($title);
184 $PAGE->set_heading($title);
185 echo $OUTPUT->header();
187 // Start the question form.
188 echo '<form method="post" action="' . $actionurl .
189         '" enctype="multipart/form-data" id="responseform">', "\n";
190 echo '<input type="hidden" name="sesskey" value="' . sesskey() . '" />', "\n";
191 echo '<input type="hidden" name="slots" value="' . $slot . '" />', "\n";
193 // Output the question.
194 echo $quba->render_question($slot, $options, $displaynumber);
196 echo '<p class="notifytiny">' . get_string('behaviourbeingused', 'question',
197         question_engine::get_behaviour_name(
198         $quba->get_question_attempt($slot)->get_behaviour_name())) . '</p>';
199 // Finish the question form.
200 echo '<div id="previewcontrols" class="controls">';
201 echo '<input type="submit" name="restart"' . $restartdisabled .
202         ' value="' . get_string('restart', 'question') . '" />', "\n";
203 echo '<input type="submit" name="fill"' . $filldisabled .
204         ' value="' . get_string('fillincorrect', 'question') . '" />', "\n";
205 echo '<input type="submit" name="finish"' . $finishdisabled .
206         ' value="' . get_string('submitandfinish', 'question') . '" />', "\n";
207 echo '<input type="hidden" name="scrollpos" id="scrollpos" value="" />';
208 echo '</div>';
209 echo '</form>';
211 // Display the settings form.
212 $optionsform->display();
214 $PAGE->requires->js_init_call('M.core_question_preview.init', null, false, array(
215         'name' => 'core_question_preview',
216         'fullpath' => '/question/preview.js',
217         'requires' => array('base', 'dom', 'event-delegate', 'event-key', 'core_question_engine'),
218         'strings' => array(
219             array('closepreview', 'question'),
220         )));
221 echo $OUTPUT->footer();