MDL-9644 new class 'moodle_url' in weblib.php to handle constructing a url. It would...
[moodle.git] / question / editlib.php
CommitLineData
516cf3eb 1<?php // $Id$
2/**
4323d029 3 * Functions used by showbank.php to show question editing interface
4 *
5 * TODO: currently the function question_list still provides controls specific
6 * to the quiz module. This needs to be generalised.
7 *
8 * @author Martin Dougiamas and many others. This has recently been extensively
9 * rewritten by members of the Serving Mathematics project
10 * {@link http://maths.york.ac.uk/serving_maths}
11 * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
12 * @package questionbank
13 */
516cf3eb 14
4fbfd971 15require_once($CFG->libdir.'/questionlib.php');
516cf3eb 16
f92cf442 17define('DEFAULT_QUESTIONS_PER_PAGE', 20);
18
4fbfd971 19/**
20* Function to read all questions for category into big array
21*
22* @param int $category category number
36e2232e 23* @param bool $noparent if true only questions with NO parent will be selected
24* @param bool $recurse include subdirectories
5fd8f999 25* @param bool $export set true if this is called by questionbank export
4fbfd971 26* @author added by Howard Miller June 2004
27*/
5fd8f999 28function get_questions_category( $category, $noparent=false, $recurse=true, $export=true ) {
4fbfd971 29
30 global $QTYPES;
31
32 // questions will be added to an array
33 $qresults = array();
34
35 // build sql bit for $noparent
36 $npsql = '';
37 if ($noparent) {
38 $npsql = " and parent='0' ";
39 }
40
36e2232e 41 // get (list) of categories
42 if ($recurse) {
43 $categorylist = question_categorylist( $category->id );
44 }
45 else {
46 $categorylist = $category->id;
47 }
48
4fbfd971 49 // get the list of questions for the category
36e2232e 50 if ($questions = get_records_select("question","category IN ($categorylist) $npsql", "qtype, name ASC")) {
4fbfd971 51
52 // iterate through questions, getting stuff we need
53 foreach($questions as $question) {
54 $questiontype = $QTYPES[$question->qtype];
5fd8f999 55 $question->export_process = $export;
4fbfd971 56 $questiontype->get_question_options( $question );
57 $qresults[] = $question;
58 }
59 }
60
61 return $qresults;
62}
63
64/**
65* Gets the default category in a course
66*
67* It returns the first category with no parent category. If no categories
68* exist yet then one is created.
69* @return object The default category
70* @param integer $courseid The id of the course whose default category is wanted
71*/
72function get_default_question_category($courseid) {
b030a630 73 // If it already exists, just return it.
74 if ($category = get_records_select("question_categories", "course = '$courseid' AND parent = '0'", 'id', '*', '', 1)) {
75 return reset($category);
4fbfd971 76 }
77
78 // Otherwise, we need to make one
b030a630 79 $category = new stdClass;
4fbfd971 80 $category->name = get_string("default", "quiz");
81 $category->info = get_string("defaultinfo", "quiz");
82 $category->course = $courseid;
83 $category->parent = 0;
b030a630 84 $category->sortorder = 999; // By default, all categories get this number, and are sorted alphabetically.
4fbfd971 85 $category->publish = 0;
86 $category->stamp = make_unique_id_code();
87
88 if (!$category->id = insert_record("question_categories", $category)) {
89 notify("Error creating a default category!");
90 return false;
91 }
92 return $category;
93}
94
4fbfd971 95/**
96 * prints a form to choose categories
97 */
624cbc9c 98function question_category_form($course, $current, $recurse=1, $showhidden=false, $showquestiontext=false) {
e586cfb4 99 global $CFG;
516cf3eb 100
101/// Make sure the default category exists for this course
b030a630 102 get_default_question_category($course->id);
516cf3eb 103
104/// Get all the existing categories now
b030a630 105 $catmenu = question_category_options($course->id, true);
dcd51df2 106
516cf3eb 107 $strcategory = get_string("category", "quiz");
108 $strshow = get_string("show", "quiz");
109 $streditcats = get_string("editcategories", "quiz");
110
0fd5feef 111 echo "<strong>$strcategory:</strong>&nbsp;";
e92d8ccf 112 popup_form ("edit.php?courseid=$course->id&amp;cat=", $catmenu, "catmenu", $current, "", "", "", false, "self");
0fd5feef 113
d2ce367f 114 echo '<form method="post" action="edit.php" id="displayoptions">';
0fd5feef 115 echo "<fieldset class='invisiblefieldset'>";
624cbc9c 116 echo "<input type=\"hidden\" name=\"courseid\" value=\"{$course->id}\" />\n";
117 question_category_form_checkbox('recurse', $recurse);
118 question_category_form_checkbox('showhidden', $showhidden);
119 question_category_form_checkbox('showquestiontext', $showquestiontext);
120 echo '<noscript><div class="centerpara"><input type="submit" value="'. get_string('go') .'" />';
121 echo '</div></noscript></fieldset></form>';
122}
123
124/**
125 * Private funciton to help the preceeding function.
126 */
127function question_category_form_checkbox($name, $checked) {
128 echo '<div><input type="hidden" id="' . $name . '_off" name="' . $name . '" value="0" />';
129 echo '<input type="checkbox" id="' . $name . '_on" name="' . $name . '" value="1"';
130 if ($checked) {
516cf3eb 131 echo ' checked="checked"';
132 }
d2ce367f 133 echo ' onchange="getElementById(\'displayoptions\').submit(); return true;" />';
624cbc9c 134 echo '<label for="' . $name . '_on">';
135 print_string($name, 'quiz');
136 echo "</label></div>\n";
516cf3eb 137}
138
516cf3eb 139/**
140* Prints the table of questions in a category with interactions
141*
142* @param object $course The course object
143* @param int $categoryid The id of the question category to be displayed
144* @param int $quizid The quiz id if we are in the context of a particular quiz, 0 otherwise
145* @param int $recurse This is 1 if subcategories should be included, 0 otherwise
146* @param int $page The number of the page to be displayed
147* @param int $perpage Number of questions to show per page
148* @param boolean $showhidden True if also hidden questions should be displayed
dcc2ffde 149* @param boolean $showquestiontext whether the text of each question should be shown in the list
516cf3eb 150*/
e49a8d09 151function question_list($course, $categoryid, $quizid=0,
624cbc9c 152 $recurse=1, $page=0, $perpage=100, $showhidden=false, $sortorder='qtype, name ASC',
153 $showquestiontext = false) {
95947ac9 154 global $QTYPE_MENU, $USER, $CFG, $THEME;
3765fd53 155
50530eb7 156 $qtypemenu = $QTYPE_MENU;
157 if ($rqp_types = get_records('question_rqp_types')) {
158 foreach($rqp_types as $type) {
159 $qtypemenu['rqp_'.$type->id] = $type->name;
160 }
161 }
162
516cf3eb 163 $strcategory = get_string("category", "quiz");
164 $strquestion = get_string("question", "quiz");
165 $straddquestions = get_string("addquestions", "quiz");
166 $strimportquestions = get_string("importquestions", "quiz");
167 $strexportquestions = get_string("exportquestions", "quiz");
168 $strnoquestions = get_string("noquestions", "quiz");
169 $strselect = get_string("select", "quiz");
170 $strselectall = get_string("selectall", "quiz");
171 $strselectnone = get_string("selectnone", "quiz");
172 $strcreatenewquestion = get_string("createnewquestion", "quiz");
173 $strquestionname = get_string("questionname", "quiz");
174 $strdelete = get_string("delete");
175 $stredit = get_string("edit");
176 $straction = get_string("action");
177 $strrestore = get_string('restore');
178
179 $straddtoquiz = get_string("addtoquiz", "quiz");
180 $strtype = get_string("type", "quiz");
181 $strcreatemultiple = get_string("createmultiple", "quiz");
182 $strpreview = get_string("preview","quiz");
183
184 if (!$categoryid) {
0fd5feef 185 echo "<p style=\"text-align:center;\"><b>";
516cf3eb 186 print_string("selectcategoryabove", "quiz");
187 echo "</b></p>";
188 if ($quizid) {
189 echo "<p>";
190 print_string("addingquestions", "quiz");
191 echo "</p>";
192 }
193 return;
194 }
195
dcc2ffde 196 if (!$category = get_record('question_categories', 'id', $categoryid)) {
197 notify('Category not found!');
516cf3eb 198 return;
199 }
dcc2ffde 200 $canedit = has_capability('moodle/question:manage', get_context_instance(CONTEXT_COURSE, $category->course));
201 $editingquiz = false;
202 if ($quizid) {
203 $cm = get_coursemodule_from_instance('quiz', $quizid);
204 $editingquiz = has_capability('mod/quiz:manage', get_context_instance(CONTEXT_MODULE, $cm->id));
205 }
206
09275894 207 echo '<div class="boxaligncenter">';
4abc23b2 208 $formatoptions = new stdClass;
7347c60b 209 $formatoptions->noclean = true;
210 echo format_text($category->info, FORMAT_MOODLE, $formatoptions, $course->id);
516cf3eb 211
212 echo '<table><tr>';
213
dcc2ffde 214 // check if editing questions in this category is allowed
215 if ($canedit) {
516cf3eb 216 echo "<td valign=\"top\"><b>$strcreatenewquestion:</b></td>";
217 echo '<td valign="top" align="right">';
50530eb7 218 popup_form ("$CFG->wwwroot/question/question.php?category=$category->id&amp;qtype=", $qtypemenu, "addquestion",
516cf3eb 219 "", "choose", "", "", false, "self");
624cbc9c 220 echo '</td><td valign="top" align="right">';
516cf3eb 221 helpbutton("questiontypes", $strcreatenewquestion, "quiz");
dcc2ffde 222 echo '</td>';
516cf3eb 223 }
224 else {
dcc2ffde 225 echo '<td>';
516cf3eb 226 print_string("publishedit","quiz");
dcc2ffde 227 echo '</td>';
516cf3eb 228 }
229
dcc2ffde 230 echo '</tr></table>';
09275894 231 echo '</div>';
516cf3eb 232
dc1f00de 233 $categorylist = ($recurse) ? question_categorylist($category->id) : $category->id;
516cf3eb 234
235 // hide-feature
236 $showhidden = $showhidden ? '' : " AND hidden = '0'";
237
4f48fb42 238 if (!$totalnumber = count_records_select('question', "category IN ($categorylist) AND parent = '0' $showhidden")) {
0fd5feef 239 echo "<p style=\"text-align:center;\">";
516cf3eb 240 print_string("noquestions", "quiz");
241 echo "</p>";
242 return;
243 }
244
4f48fb42 245 if (!$questions = get_records_select('question', "category IN ($categorylist) AND parent = '0' $showhidden", $sortorder, '*', $page*$perpage, $perpage)) {
516cf3eb 246 // There are no questions on the requested page.
247 $page = 0;
4f48fb42 248 if (!$questions = get_records_select('question', "category IN ($categorylist) AND parent = '0' $showhidden", $sortorder, '*', 0, $perpage)) {
516cf3eb 249 // There are no questions at all
0fd5feef 250 echo "<p style=\"text-align:center;\">";
516cf3eb 251 print_string("noquestions", "quiz");
252 echo "</p>";
253 return;
254 }
255 }
256
257 print_paging_bar($totalnumber, $page, $perpage,
a0e512fe 258 "edit.php?courseid={$course->id}&amp;perpage=$perpage&amp;");
516cf3eb 259
5bbca3a4 260 echo '<form method="post" action="edit.php?courseid='.$course->id.'">';
624cbc9c 261 echo '<fieldset class="invisiblefieldset" style="display: block;">';
516cf3eb 262 echo '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />';
5eb266d8 263
624cbc9c 264 echo '<table id="categoryquestions" style="width: 100%"><tr>';
265 echo "<th style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">$straction</th>";
516cf3eb 266
267 $sortoptions = array('name, qtype ASC' => get_string("sortalpha", "quiz"),
268 'qtype, name ASC' => get_string("sorttypealpha", "quiz"),
269 'id ASC' => get_string("sortage", "quiz"));
270 $orderselect = choose_from_menu ($sortoptions, 'sortorder', $sortorder, false, 'this.form.submit();', '0', true);
09275894 271 $orderselect .= '<noscript><div><input type="submit" value="'.get_string("sortsubmit", "quiz").'" /></div></noscript>';
624cbc9c 272 echo "<th style=\"white-space:nowrap; text-align: left;\" class=\"header\" scope=\"col\">$strquestionname $orderselect</th>
273 <th style=\"white-space:nowrap; text-align: right;\" class=\"header\" scope=\"col\">$strtype</th>";
516cf3eb 274 echo "</tr>\n";
275 foreach ($questions as $question) {
624cbc9c 276 $nameclass = '';
277 $textclass = '';
278 if ($question->hidden) {
279 $nameclass = 'dimmed_text';
280 $textclass = 'dimmed_text';
281 }
282 if ($showquestiontext) {
283 $nameclass .= ' header';
284 }
285 if ($nameclass) {
286 $nameclass = 'class="' . $nameclass . '"';
287 }
288 if ($textclass) {
289 $textclass = 'class="' . $textclass . '"';
290 }
291
292 echo "<tr>\n<td style=\"white-space:nowrap;\" $nameclass>\n";
3765fd53 293
294 // add to quiz
dcc2ffde 295 if ($editingquiz) {
e3aea79a 296 echo "<a title=\"$straddtoquiz\" href=\"edit.php?addquestion=$question->id&amp;quizid=$quizid&amp;sesskey=$USER->sesskey\"><img
0fd5feef 297 src=\"$CFG->pixpath/t/moveleft.gif\" alt=\"$straddtoquiz\" /></a>&nbsp;";
516cf3eb 298 }
3765fd53 299
300 // preview
7d87171b 301 link_to_popup_window('/question/preview.php?id=' . $question->id . '&amp;quizid=' . $quizid, 'questionpreview',
302 "<img src=\"$CFG->pixpath/t/preview.gif\" class=\"iconsmall\" alt=\"$strpreview\" />",
303 0, 0, $strpreview, QUESTION_PREVIEW_POPUP_OPTIONS);
3765fd53 304
305 // edit, hide, delete question, using question capabilities, not quiz capabilieies
dcc2ffde 306 if ($canedit) {
e586cfb4 307 echo "<a title=\"$stredit\" href=\"$CFG->wwwroot/question/question.php?id=$question->id\"><img
0fd5feef 308 src=\"$CFG->pixpath/t/edit.gif\" alt=\"$stredit\" /></a>&nbsp;";
516cf3eb 309 // hide-feature
310 if($question->hidden) {
e3aea79a 311 echo "<a title=\"$strrestore\" href=\"edit.php?courseid=$course->id&amp;unhide=$question->id&amp;sesskey=$USER->sesskey\"><img
0fd5feef 312 src=\"$CFG->pixpath/t/restore.gif\" alt=\"$strrestore\" /></a>";
516cf3eb 313 } else {
e3aea79a 314 echo "<a title=\"$strdelete\" href=\"edit.php?courseid=$course->id&amp;deleteselected=$question->id&amp;q$question->id=1\"><img
0fd5feef 315 src=\"$CFG->pixpath/t/delete.gif\" alt=\"$strdelete\" /></a>";
516cf3eb 316 }
317 }
318 echo "&nbsp;<input title=\"$strselect\" type=\"checkbox\" name=\"q$question->id\" value=\"1\" />";
319 echo "</td>\n";
320
70ed7667 321 echo "<td $nameclass>" . format_string($question->name) . "</td>\n";
624cbc9c 322 echo "<td $nameclass style='text-align: right'>\n";
dcc2ffde 323 print_question_icon($question);
516cf3eb 324 echo "</td>\n";
325 echo "</tr>\n";
624cbc9c 326 if($showquestiontext){
327 echo '<tr><td colspan="3" ' . $textclass . '>';
328 $formatoptions = new stdClass;
329 $formatoptions->noclean = true;
330 $formatoptions->para = false;
331 echo format_text($question->questiontext, $question->questiontextformat,
332 $formatoptions, $course->id);
333 echo "</td></tr>\n";
334 }
516cf3eb 335 }
624cbc9c 336 echo "</table>\n";
624cbc9c 337
338 $paging = print_paging_bar($totalnumber, $page, $perpage,
339 "edit.php?courseid={$course->id}&amp;perpage=$perpage&amp;", 'page',
340 false, true);
f92cf442 341 if ($totalnumber > DEFAULT_QUESTIONS_PER_PAGE) {
342 if ($perpage == DEFAULT_QUESTIONS_PER_PAGE) {
624cbc9c 343 $showall = '<a href="edit.php?courseid='.$course->id.'&amp;perpage=1000">'.get_string('showall', 'moodle', $totalnumber).'</a>';
f92cf442 344 } else {
624cbc9c 345 $showall = '<a href="edit.php?courseid='.$course->id.'&amp;perpage=' . DEFAULT_QUESTIONS_PER_PAGE . '">'.get_string('showperpage', 'moodle', DEFAULT_QUESTIONS_PER_PAGE).'</a>';
346 }
347 if ($paging) {
348 $paging = substr($paging, 0, strrpos($paging, '</div>'));
349 $paging .= "<br />$showall</div>";
350 } else {
351 $paging = "<div class='paging'>$showall</div>";
f92cf442 352 }
3abfa3a0 353 }
624cbc9c 354 echo $paging;
516cf3eb 355
356 echo '<table class="quiz-edit-selected"><tr><td colspan="2">';
357 echo '<a href="javascript:select_all_in(\'TABLE\', null, \'categoryquestions\');">'.$strselectall.'</a> /'.
358 ' <a href="javascript:deselect_all_in(\'TABLE\', null, \'categoryquestions\');">'.$strselectnone.'</a>'.
359 '</td><td align="right"><b>&nbsp;'.get_string('withselected', 'quiz').':</b></td></tr><tr><td>';
95947ac9 360
dcc2ffde 361 if ($editingquiz) {
95947ac9 362 echo "<input type=\"submit\" name=\"add\" value=\"{$THEME->larrow} $straddtoquiz\" />\n";
516cf3eb 363 echo '</td><td>';
364 }
3765fd53 365 // print delete and move selected question
dcc2ffde 366 if ($canedit) {
516cf3eb 367 echo '<input type="submit" name="deleteselected" value="'.$strdelete."\" /></td><td>\n";
368 echo '<input type="submit" name="move" value="'.get_string('moveto', 'quiz')."\" />\n";
dc1f00de 369 question_category_select_menu($course->id, false, true, $category->id);
516cf3eb 370 }
371 echo "</td></tr></table>";
372
3765fd53 373 // add random question
dcc2ffde 374 if ($editingquiz) {
b28e2577 375 for ($i = 1;$i <= min(10, $totalnumber); $i++) {
376 $randomcount[$i] = $i;
377 }
378 for ($i = 20;$i <= min(100, $totalnumber); $i += 10) {
516cf3eb 379 $randomcount[$i] = $i;
380 }
381 echo '<br />';
382 print_string('addrandom', 'quiz',
383 choose_from_menu($randomcount, 'randomcount', '1', '', '', '', true));
384 echo '<input type="hidden" name="recurse" value="'.$recurse.'" />';
385 echo "<input type=\"hidden\" name=\"categoryid\" value=\"$category->id\" />";
386 echo ' <input type="submit" name="addrandom" value="'. get_string('add') .'" />';
387 helpbutton('random', get_string('random', 'quiz'), 'quiz');
388 }
09275894 389 echo '</fieldset>';
390 echo "</form>\n";
516cf3eb 391}
392
5fd8f999 393?>