|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 // This file is part of Moodle - http://moodle.org/ 00003 // 00004 // Moodle is free software: you can redistribute it and/or modify 00005 // it under the terms of the GNU General Public License as published by 00006 // the Free Software Foundation, either version 3 of the License, or 00007 // (at your option) any later version. 00008 // 00009 // Moodle is distributed in the hope that it will be useful, 00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of 00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 00012 // GNU General Public License for more details. 00013 // 00014 // You should have received a copy of the GNU General Public License 00015 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 00016 00033 require_once(dirname(__FILE__) . '/../config.php'); 00034 require_once($CFG->libdir . '/questionlib.php'); 00035 require_once(dirname(__FILE__) . '/previewlib.php'); 00036 00042 define('QUESTION_PREVIEW_MAX_VARIANTS', 100); 00043 00044 // Get and validate question id. 00045 $id = required_param('id', PARAM_INT); 00046 $question = question_bank::load_question($id); 00047 00048 // Were we given a particular context to run the question in? 00049 // This affects things like filter settings, or forced theme or language. 00050 if ($cmid = optional_param('cmid', 0, PARAM_INT)) { 00051 $cm = get_coursemodule_from_id(false, $cmid); 00052 require_login($cm->course, false, $cm); 00053 $context = get_context_instance(CONTEXT_MODULE, $cmid); 00054 00055 } else if ($courseid = optional_param('courseid', 0, PARAM_INT)) { 00056 require_login($courseid); 00057 $context = get_context_instance(CONTEXT_COURSE, $courseid); 00058 00059 } else { 00060 require_login(); 00061 $category = $DB->get_record('question_categories', 00062 array('id' => $question->category), '*', MUST_EXIST); 00063 $context = get_context_instance_by_id($category->contextid); 00064 $PAGE->set_context($context); 00065 // Note that in the other cases, require_login will set the correct page context. 00066 } 00067 question_require_capability_on($question, 'use'); 00068 $PAGE->set_pagelayout('popup'); 00069 00070 // Get and validate display options. 00071 $maxvariant = min($question->get_num_variants(), QUESTION_PREVIEW_MAX_VARIANTS); 00072 $options = new question_preview_options($question); 00073 $options->load_user_defaults(); 00074 $options->set_from_request(); 00075 $PAGE->set_url(question_preview_url($id, $options->behaviour, $options->maxmark, 00076 $options, $options->variant, $context)); 00077 00078 // Get and validate exitsing preview, or start a new one. 00079 $previewid = optional_param('previewid', 0, PARAM_INT); 00080 00081 if ($previewid) { 00082 if (!isset($SESSION->question_previews[$previewid])) { 00083 print_error('notyourpreview', 'question'); 00084 } 00085 00086 try { 00087 $quba = question_engine::load_questions_usage_by_activity($previewid); 00088 00089 } catch (Exception $e) { 00090 // This may not seem like the right error message to display, but 00091 // actually from the user point of view, it makes sense. 00092 print_error('submissionoutofsequencefriendlymessage', 'question', 00093 question_preview_url($question->id, $options->behaviour, 00094 $options->maxmark, $options, $options->variant, $context), null, $e); 00095 } 00096 00097 $slot = $quba->get_first_question_number(); 00098 $usedquestion = $quba->get_question($slot); 00099 if ($usedquestion->id != $question->id) { 00100 print_error('questionidmismatch', 'question'); 00101 } 00102 $question = $usedquestion; 00103 $options->variant = $quba->get_variant($slot); 00104 00105 } else { 00106 $quba = question_engine::make_questions_usage_by_activity( 00107 'core_question_preview', $context); 00108 $quba->set_preferred_behaviour($options->behaviour); 00109 $slot = $quba->add_question($question, $options->maxmark); 00110 00111 if ($options->variant) { 00112 $options->variant = min($maxvariant, max(1, $options->variant)); 00113 } else { 00114 $options->variant = rand(1, $maxvariant); 00115 } 00116 00117 $quba->start_question($slot, $options->variant); 00118 00119 $transaction = $DB->start_delegated_transaction(); 00120 question_engine::save_questions_usage_by_activity($quba); 00121 $transaction->allow_commit(); 00122 00123 $SESSION->question_previews[$quba->get_id()] = true; 00124 } 00125 $options->behaviour = $quba->get_preferred_behaviour(); 00126 $options->maxmark = $quba->get_question_max_mark($slot); 00127 00128 // Create the settings form, and initialise the fields. 00129 $optionsform = new preview_options_form(question_preview_form_url($question->id, $context), 00130 array('quba' => $quba, 'maxvariant' => $maxvariant)); 00131 $optionsform->set_data($options); 00132 00133 // Process change of settings, if that was requested. 00134 if ($newoptions = $optionsform->get_submitted_data()) { 00135 // Set user preferences 00136 $options->save_user_preview_options($newoptions); 00137 if (!isset($newoptions->variant)) { 00138 $newoptions->variant = $options->variant; 00139 } 00140 restart_preview($previewid, $question->id, $newoptions, $context); 00141 } 00142 00143 // Prepare a URL that is used in various places. 00144 $actionurl = question_preview_action_url($question->id, $quba->get_id(), $options, $context); 00145 00146 // Process any actions from the buttons at the bottom of the form. 00147 if (data_submitted() && confirm_sesskey()) { 00148 00149 try { 00150 00151 if (optional_param('restart', false, PARAM_BOOL)) { 00152 restart_preview($previewid, $question->id, $options, $context); 00153 00154 } else if (optional_param('fill', null, PARAM_BOOL)) { 00155 $correctresponse = $quba->get_correct_response($slot); 00156 if (!is_null($correctresponse)) { 00157 $quba->process_action($slot, $correctresponse); 00158 00159 $transaction = $DB->start_delegated_transaction(); 00160 question_engine::save_questions_usage_by_activity($quba); 00161 $transaction->allow_commit(); 00162 } 00163 redirect($actionurl); 00164 00165 } else if (optional_param('finish', null, PARAM_BOOL)) { 00166 $quba->process_all_actions(); 00167 $quba->finish_all_questions(); 00168 00169 $transaction = $DB->start_delegated_transaction(); 00170 question_engine::save_questions_usage_by_activity($quba); 00171 $transaction->allow_commit(); 00172 redirect($actionurl); 00173 00174 } else { 00175 $quba->process_all_actions(); 00176 00177 $transaction = $DB->start_delegated_transaction(); 00178 question_engine::save_questions_usage_by_activity($quba); 00179 $transaction->allow_commit(); 00180 00181 $scrollpos = optional_param('scrollpos', '', PARAM_RAW); 00182 if ($scrollpos !== '') { 00183 $actionurl->param('scrollpos', (int) $scrollpos); 00184 } 00185 redirect($actionurl); 00186 } 00187 00188 } catch (question_out_of_sequence_exception $e) { 00189 print_error('submissionoutofsequencefriendlymessage', 'question', $actionurl); 00190 00191 } catch (Exception $e) { 00192 // This sucks, if we display our own custom error message, there is no way 00193 // to display the original stack trace. 00194 $debuginfo = ''; 00195 if (!empty($e->debuginfo)) { 00196 $debuginfo = $e->debuginfo; 00197 } 00198 print_error('errorprocessingresponses', 'question', $actionurl, 00199 $e->getMessage(), $debuginfo); 00200 } 00201 } 00202 00203 if ($question->length) { 00204 $displaynumber = '1'; 00205 } else { 00206 $displaynumber = 'i'; 00207 } 00208 $restartdisabled = ''; 00209 $finishdisabled = ''; 00210 $filldisabled = ''; 00211 if ($quba->get_question_state($slot)->is_finished()) { 00212 $finishdisabled = ' disabled="disabled"'; 00213 $filldisabled = ' disabled="disabled"'; 00214 } 00215 // If question type cannot give us a correct response, disable this button. 00216 if (is_null($quba->get_correct_response($slot))) { 00217 $filldisabled = ' disabled="disabled"'; 00218 } 00219 if (!$previewid) { 00220 $restartdisabled = ' disabled="disabled"'; 00221 } 00222 00223 // Output 00224 $title = get_string('previewquestion', 'question', format_string($question->name)); 00225 $headtags = question_engine::initialise_js() . $quba->render_question_head_html($slot); 00226 $PAGE->set_title($title); 00227 $PAGE->set_heading($title); 00228 echo $OUTPUT->header(); 00229 00230 // Start the question form. 00231 echo '<form method="post" action="' . $actionurl . 00232 '" enctype="multipart/form-data" id="responseform">', "\n"; 00233 echo '<div>'; 00234 echo '<input type="hidden" name="sesskey" value="' . sesskey() . '" />', "\n"; 00235 echo '<input type="hidden" name="slots" value="' . $slot . '" />', "\n"; 00236 echo '</div>'; 00237 00238 // Output the question. 00239 echo $quba->render_question($slot, $options, $displaynumber); 00240 00241 echo '<p class="notifytiny">' . get_string('behaviourbeingused', 'question', 00242 question_engine::get_behaviour_name( 00243 $quba->get_question_attempt($slot)->get_behaviour_name())) . '</p>'; 00244 // Finish the question form. 00245 echo '<div id="previewcontrols" class="controls">'; 00246 echo '<input type="submit" name="restart"' . $restartdisabled . 00247 ' value="' . get_string('restart', 'question') . '" />', "\n"; 00248 echo '<input type="submit" name="fill"' . $filldisabled . 00249 ' value="' . get_string('fillincorrect', 'question') . '" />', "\n"; 00250 echo '<input type="submit" name="finish"' . $finishdisabled . 00251 ' value="' . get_string('submitandfinish', 'question') . '" />', "\n"; 00252 echo '<input type="hidden" name="scrollpos" id="scrollpos" value="" />'; 00253 echo '</div>'; 00254 echo '</form>'; 00255 00256 // Display the settings form. 00257 $optionsform->display(); 00258 00259 $PAGE->requires->js_init_call('M.core_question_preview.init', null, false, array( 00260 'name' => 'core_question_preview', 00261 'fullpath' => '/question/preview.js', 00262 'requires' => array('base', 'dom', 'event-delegate', 'event-key', 'core_question_engine'), 00263 'strings' => array( 00264 array('closepreview', 'question'), 00265 ))); 00266 echo $OUTPUT->footer(); 00267