protected function display_content($question, $rowclasses) { if (!question_has_capability_on($question, 'use')) { return; } $this->print_icon('t/add', $this->stradd, $this->qbank->add_to_rtq_url($question->id)); }
protected function display_content($question, $rowclasses) { global $PAGE; if (question_has_capability_on($question, 'use')) { echo $PAGE->get_renderer('core_question')->question_preview_link($question->id, $this->qbank->get_most_specific_context(), false); } }
function print_question(&$question, &$state, $number, $cmoptions, $options) { global $CFG; $isfinished = question_state_is_graded($state->last_graded) || $state->event == QUESTION_EVENTCLOSE; if (!empty($cmoptions->id)) { $cm = get_coursemodule_from_instance('quiz', $cmoptions->id); $cmorcourseid = '&cmid=' . $cm->id; } else { if (!empty($cmoptions->course)) { $cmorcourseid = '&courseid=' . $cmoptions->course; } else { error('Need to provide courseid or cmid to print_question.'); } } // For editing teachers print a link to an editing popup window $editlink = ''; if (question_has_capability_on($question, 'edit')) { $stredit = get_string('edit'); $linktext = '<img src="' . $CFG->pixpath . '/t/edit.gif" alt="' . $stredit . '" />'; $editlink = link_to_popup_window('/question/question.php?id=' . $question->id . $cmorcourseid, $stredit, $linktext, 450, 550, $stredit, '', true); } $questiontext = $this->format_text($question->questiontext, $question->questiontextformat, $cmoptions); $image = get_question_image($question); $generalfeedback = ''; if ($isfinished && $options->generalfeedback) { $generalfeedback = $this->format_text($question->generalfeedback, $question->questiontextformat, $cmoptions); } include "{$CFG->dirroot}/question/type/description/question.html"; }
/** * Called via pluginfile.php -> question_pluginfile to serve files belonging to * a question in a question_attempt when that attempt is a preview. * * @param object $course course settings object * @param object $context context object * @param string $component the name of the component we are serving files for. * @param string $filearea the name of the file area. * @param array $args the remaining bits of the file path. * @param bool $forcedownload whether the user must be forced to download the file. * @return bool false if file not found, does not return if found - justsend the file */ function question_preview_question_pluginfile($course, $context, $component, $filearea, $attemptid, $questionid, $args, $forcedownload) { global $USER, $SESSION, $DB, $CFG; require_once $CFG->dirroot . '/mod/quiz/locallib.php'; if (!($question = $DB->get_record('question', array('id' => $questionid)))) { return send_file_not_found(); } if (!question_has_capability_on($question, 'use', $question->category)) { send_file_not_found(); } if (!isset($SESSION->quizpreview->states) || $SESSION->quizpreview->questionid != $questionid) { send_file_not_found(); } $states = end($SESSION->quizpreview->states); if (!array_key_exists($question->id, $states)) { send_file_not_found(); } $state = $states[$question->id]; // Build fake cmoptions $quiz = new cmoptions(); $quiz->id = 0; $quiz->review = get_config('quiz', 'review'); if (empty($course->id)) { $quiz->course = SITEID; } else { $quiz->course = $course->id; } $quiz->decimalpoints = get_config('quiz', 'decimalpoints'); $questions[$question->id] = $question; get_question_options($questions); // Build fake attempt $timenow = time(); $attempt = new stdClass(); $attempt->quiz = $quiz->id; $attempt->userid = $USER->id; $attempt->attempt = 0; $attempt->sumgrades = 0; $attempt->timestart = $timenow; $attempt->timefinish = 0; $attempt->timemodified = $timenow; $attempt->uniqueid = 0; $attempt->id = 0; $attempt->layout = $question->id; $options = quiz_get_renderoptions($quiz, $attempt, $context, $state); $options->noeditlink = true; // XXX: mulitichoice type needs quiz id to get maxgrade $options->quizid = 0; if (!question_check_file_access($question, $state, $options, $context->id, $component, $filearea, $args, $forcedownload)) { send_file_not_found(); } $fs = get_file_storage(); $relativepath = implode('/', $args); $fullpath = "/{$context->id}/{$component}/{$filearea}/{$relativepath}"; if (!($file = $fs->get_file_by_hash(sha1($fullpath))) or $file->is_directory()) { send_file_not_found(); } send_stored_file($file, 0, 0, $forcedownload); }
protected function display_content($question, $rowclasses) { // To copy a question, you need permission to add a question in the same // category as the existing question, and ability to access the details of // the question being copied. if (question_has_capability_on($question, 'add') && (question_has_capability_on($question, 'edit') || question_has_capability_on($question, 'view'))) { $this->print_icon('t/copy', $this->strcopy, $this->qbank->copy_question_url($question->id)); } }
protected function display_content($question, $rowclasses) { if (question_has_capability_on($question, 'edit')) { $this->print_icon('t/edit', $this->stredit, $this->qbank->edit_question_url($question->id)); } else { if (question_has_capability_on($question, 'view')) { $this->print_icon('i/info', $this->strview, $this->qbank->edit_question_url($question->id)); } } }
function drop_questions($a) { global $DB; // First sanity check the existance of the context. there may be deleted contexts and some question wreck inside. $contextid = $DB->get_field('question_categories', 'contextid', array('id' => $a->category)); if (!$DB->record_exists('context', array('id' => $contextid))) { return false; } return question_has_capability_on($a->id, 'use'); }
protected function display_content($question, $rowclasses) { if (!question_has_capability_on($question, 'use')) { return; } $disabled = false; if ($this->qbank->offlinequiz_contains($question->id)) { $disabled = true; } $this->print_icon('t/add', $this->stradd, $this->qbank->add_to_offlinequiz_url($question->id), $disabled); }
protected function display_content($question, $rowclasses) { if (question_has_capability_on($question, 'edit')) { if ($question->hidden) { $url = new \moodle_url($this->qbank->base_url(), array('unhide' => $question->id, 'sesskey' => sesskey())); $this->print_icon('t/restore', $this->strrestore, $url); } else { $url = new \moodle_url($this->qbank->base_url(), array('deleteselected' => $question->id, 'q' . $question->id => 1, 'sesskey' => sesskey())); $this->print_icon('t/delete', $this->strdelete, $url); } } }
$categorycontext = get_context_instance_by_id($category->contextid); $addpermission = has_capability('moodle/question:add', $categorycontext); if ($id) { $canview = question_has_capability_on($question, 'view'); if ($movecontext) { $question->formoptions->canedit = false; $question->formoptions->canmove = question_has_capability_on($question, 'move') && $contexts->have_cap('moodle/question:add'); $question->formoptions->cansaveasnew = false; $question->formoptions->repeatelements = false; $question->formoptions->movecontext = true; $formeditable = true; question_require_capability_on($question, 'view'); } else { $question->formoptions->canedit = question_has_capability_on($question, 'edit'); $question->formoptions->canmove = question_has_capability_on($question, 'move') && $addpermission; $question->formoptions->cansaveasnew = ($canview || question_has_capability_on($question, 'edit')) && $addpermission; $question->formoptions->repeatelements = $question->formoptions->canedit || $question->formoptions->cansaveasnew; $formeditable = $question->formoptions->canedit || $question->formoptions->cansaveasnew || $question->formoptions->canmove; $question->formoptions->movecontext = false; if (!$formeditable) { question_require_capability_on($question, 'view'); } } } else { // creating a new question require_capability('moodle/question:add', $categorycontext); $formeditable = true; $question->formoptions->repeatelements = true; $question->formoptions->movecontext = false; } // Validate the question type.
/** * Get a link to an edit icon for this question, if the current user is allowed * to edit it. * * @param object $question the question object. * @param object $cmoptions the options from the module. If $cmoptions->thispageurl is set * then the link will be to edit the question in this browser window, then return to * $cmoptions->thispageurl. Otherwise the link will be to edit in a popup. $cmoptions->cmid should also be set. * @return string the HTML of the link, or nothing it the currenty user is not allowed to edit. */ function get_question_edit_link($question, $cmoptions, $options) { global $CFG; /// Is this user allowed to edit this question? if (!empty($options->noeditlink) || !question_has_capability_on($question, 'edit')) { return ''; } /// Work out the right URL. $linkurl = '/question/question.php?id=' . $question->id; if (!empty($cmoptions->cmid)) { $linkurl .= '&cmid=' . $cmoptions->cmid; } else { if (!empty($cmoptions->course)) { $linkurl .= '&courseid=' . $cmoptions->course; } else { error('Need to provide courseid or cmid to get_question_edit_link.'); } } /// Work out the contents of the link. $stredit = get_string('edit'); $linktext = '<img src="' . $CFG->pixpath . '/t/edit.gif" alt="' . $stredit . '" />'; if (!empty($cmoptions->thispageurl)) { /// The module allow editing in the same window, print an ordinary link. return '<a href="' . $CFG->wwwroot . $linkurl . '&returnurl=' . urlencode($cmoptions->thispageurl) . '" title="' . $stredit . '">' . $linktext . '</a>'; } else { /// We have to edit in a pop-up. return link_to_popup_window($linkurl . '&inpopup=1', 'editquestion', $linktext, false, false, $stredit, '', true); } }
/** * Require capability on question. */ function question_require_capability_on($question, $cap) { if (!question_has_capability_on($question, $cap)) { print_error('nopermissions', '', '', $cap); } return true; }
/** * Prints the table of questions in a category with interactions * * @param object $course The course object * @param int $categoryid The id of the question category to be displayed * @param int $cm The course module record if we are in the context of a particular module, 0 otherwise * @param int $recurse This is 1 if subcategories should be included, 0 otherwise * @param int $page The number of the page to be displayed * @param int $perpage Number of questions to show per page * @param boolean $showhidden True if also hidden questions should be displayed * @param boolean $showquestiontext whether the text of each question should be shown in the list */ function question_list($contexts, $pageurl, $categoryandcontext, $cm = null, $recurse = 1, $page = 0, $perpage = 100, $showhidden = false, $sortorder = 'typename', $sortorderdecoded = 'qtype, name ASC', $showquestiontext = false, $addcontexts = array()) { global $USER, $CFG, $THEME, $COURSE; $lastchangedid = optional_param('lastchanged', 0, PARAM_INT); list($categoryid, $contextid) = explode(',', $categoryandcontext); $qtypemenu = question_type_menu(); $strcategory = get_string("category", "quiz"); $strquestion = get_string("question", "quiz"); $straddquestions = get_string("addquestions", "quiz"); $strimportquestions = get_string("importquestions", "quiz"); $strexportquestions = get_string("exportquestions", "quiz"); $strnoquestions = get_string("noquestions", "quiz"); $strselect = get_string("select", "quiz"); $strselectall = get_string("selectall", "quiz"); $strselectnone = get_string("selectnone", "quiz"); $strcreatenewquestion = get_string("createnewquestion", "quiz"); $strquestionname = get_string("questionname", "quiz"); $strdelete = get_string("delete"); $stredit = get_string("edit"); $strmove = get_string('moveqtoanothercontext', 'question'); $strview = get_string("view"); $straction = get_string("action"); $strrestore = get_string('restore'); $strtype = get_string("type", "quiz"); $strcreatemultiple = get_string("createmultiple", "quiz"); $strpreview = get_string("preview", "quiz"); if (!$categoryid) { echo "<p style=\"text-align:center;\"><b>"; print_string("selectcategoryabove", "quiz"); echo "</b></p>"; return; } if (!($category = get_record('question_categories', 'id', $categoryid, 'contextid', $contextid))) { notify('Category not found!'); return; } $catcontext = get_context_instance_by_id($contextid); $canadd = has_capability('moodle/question:add', $catcontext); //check for capabilities on all questions in category, will also apply to sub cats. $caneditall = has_capability('moodle/question:editall', $catcontext); $canuseall = has_capability('moodle/question:useall', $catcontext); $canmoveall = has_capability('moodle/question:moveall', $catcontext); if ($cm and $cm->modname == 'quiz') { $quizid = $cm->instance; } else { $quizid = 0; } $returnurl = $pageurl->out(); $questionurl = new moodle_url("{$CFG->wwwroot}/question/question.php", array('returnurl' => $returnurl)); if ($cm !== null) { $questionurl->param('cmid', $cm->id); } else { $questionurl->param('courseid', $COURSE->id); } $questionmoveurl = new moodle_url("{$CFG->wwwroot}/question/contextmoveq.php", array('returnurl' => $returnurl)); if ($cm !== null) { $questionmoveurl->param('cmid', $cm->id); } else { $questionmoveurl->param('courseid', $COURSE->id); } echo '<div class="boxaligncenter">'; $formatoptions = new stdClass(); $formatoptions->noclean = true; echo format_text($category->info, FORMAT_MOODLE, $formatoptions, $COURSE->id); echo '<table><tr>'; if ($canadd) { echo '<td valign="top" align="right">'; popup_form($questionurl->out(false, array('category' => $category->id)) . '&qtype=', $qtypemenu, "addquestion", "", "choose", "", "", false, "self", "<strong>{$strcreatenewquestion}</strong>"); echo '</td><td valign="top" align="right">'; helpbutton("questiontypes", $strcreatenewquestion, "quiz"); echo '</td>'; } else { echo '<td>'; print_string('nopermissionadd', 'question'); echo '</td>'; } echo '</tr></table>'; echo '</div>'; $categorylist = $recurse ? question_categorylist($category->id) : $category->id; // hide-feature $showhidden = $showhidden ? '' : " AND hidden = '0'"; if (!($totalnumber = count_records_select('question', "category IN ({$categorylist}) AND parent = '0' {$showhidden}"))) { echo "<p style=\"text-align:center;\">"; print_string("noquestions", "quiz"); echo "</p>"; return; } if (!($questions = get_records_select('question', "category IN ({$categorylist}) AND parent = '0' {$showhidden}", $sortorderdecoded, '*', $page * $perpage, $perpage))) { // There are no questions on the requested page. $page = 0; if (!($questions = get_records_select('question', "category IN ({$categorylist}) AND parent = '0' {$showhidden}", $sortorderdecoded, '*', 0, $perpage))) { // There are no questions at all echo "<p style=\"text-align:center;\">"; print_string("noquestions", "quiz"); echo "</p>"; return; } } print_paging_bar($totalnumber, $page, $perpage, $pageurl, 'qpage'); echo question_sort_options($pageurl, $sortorder); echo '<form method="post" action="edit.php">'; echo '<fieldset class="invisiblefieldset" style="display: block;">'; echo '<input type="hidden" name="sesskey" value="' . $USER->sesskey . '" />'; echo $pageurl->hidden_params_out(); echo '<table id="categoryquestions" style="width: 100%"><tr>'; echo "<th style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">{$straction}</th>"; echo "<th style=\"white-space:nowrap; text-align: left;\" class=\"header\" scope=\"col\">{$strquestionname}</th>\n <th style=\"white-space:nowrap; text-align: right;\" class=\"header\" scope=\"col\">{$strtype}</th>"; echo "</tr>\n"; foreach ($questions as $question) { $nameclass = ''; $textclass = ''; if ($question->hidden) { $nameclass = 'dimmed_text'; $textclass = 'dimmed_text'; } if ($showquestiontext) { $nameclass .= ' header'; } if ($question->id == $lastchangedid) { $nameclass = 'highlight'; } if ($nameclass) { $nameclass = 'class="' . $nameclass . '"'; } if ($textclass) { $textclass = 'class="' . $textclass . '"'; } echo "<tr>\n<td style=\"white-space:nowrap;\" {$nameclass}>\n"; $canuseq = question_has_capability_on($question, 'use', $question->category); if (function_exists('module_specific_actions')) { echo module_specific_actions($pageurl, $question->id, $cm->id, $canuseq); } // preview if ($canuseq) { $quizorcourseid = $quizid ? '&quizid=' . $quizid : '&courseid=' . $COURSE->id; link_to_popup_window('/question/preview.php?id=' . $question->id . $quizorcourseid, 'questionpreview', "<img src=\"{$CFG->pixpath}/t/preview.gif\" class=\"iconsmall\" alt=\"{$strpreview}\" />", 0, 0, $strpreview, QUESTION_PREVIEW_POPUP_OPTIONS); } // edit, hide, delete question, using question capabilities, not quiz capabilieies if (question_has_capability_on($question, 'edit', $question->category) || question_has_capability_on($question, 'move', $question->category)) { echo "<a title=\"{$stredit}\" href=\"" . $questionurl->out(false, array('id' => $question->id)) . "\"><img\n src=\"{$CFG->pixpath}/t/edit.gif\" alt=\"{$stredit}\" /></a> "; } elseif (question_has_capability_on($question, 'view', $question->category)) { echo "<a title=\"{$strview}\" href=\"" . $questionurl->out(false, array('id' => $question->id)) . "\"><img\n src=\"{$CFG->pixpath}/i/info.gif\" alt=\"{$strview}\" /></a> "; } if (question_has_capability_on($question, 'move', $question->category) && question_has_capability_on($question, 'view', $question->category)) { echo "<a title=\"{$strmove}\" href=\"" . $questionurl->out(false, array('id' => $question->id, 'movecontext' => 1)) . "\"><img\n src=\"{$CFG->pixpath}/t/move.gif\" alt=\"{$strmove}\" /></a> "; } if (question_has_capability_on($question, 'edit', $question->category)) { // hide-feature if ($question->hidden) { echo "<a title=\"{$strrestore}\" href=\"edit.php?" . $pageurl->get_query_string() . "&unhide={$question->id}&sesskey={$USER->sesskey}\"><img\n src=\"{$CFG->pixpath}/t/restore.gif\" alt=\"{$strrestore}\" /></a>"; } else { echo "<a title=\"{$strdelete}\" href=\"edit.php?" . $pageurl->get_query_string() . "&deleteselected={$question->id}&q{$question->id}=1\"><img\n src=\"{$CFG->pixpath}/t/delete.gif\" alt=\"{$strdelete}\" /></a>"; } } if ($caneditall || $canmoveall || $canuseall) { echo " <input title=\"{$strselect}\" type=\"checkbox\" name=\"q{$question->id}\" value=\"1\" />"; } echo "</td>\n"; echo "<td {$nameclass}>" . format_string($question->name) . "</td>\n"; echo "<td {$nameclass} style='text-align: right'>\n"; print_question_icon($question); echo "</td>\n"; echo "</tr>\n"; if ($showquestiontext) { echo '<tr><td colspan="3" ' . $textclass . '>'; $formatoptions = new stdClass(); $formatoptions->noclean = true; $formatoptions->para = false; echo format_text($question->questiontext, $question->questiontextformat, $formatoptions, $COURSE->id); echo "</td></tr>\n"; } } echo "</table>\n"; $paging = print_paging_bar($totalnumber, $page, $perpage, $pageurl, 'qpage', false, true); if ($totalnumber > DEFAULT_QUESTIONS_PER_PAGE) { if ($perpage == DEFAULT_QUESTIONS_PER_PAGE) { $showall = '<a href="edit.php?' . $pageurl->get_query_string(array('qperpage' => 1000)) . '">' . get_string('showall', 'moodle', $totalnumber) . '</a>'; } else { $showall = '<a href="edit.php?' . $pageurl->get_query_string(array('qperpage' => DEFAULT_QUESTIONS_PER_PAGE)) . '">' . get_string('showperpage', 'moodle', DEFAULT_QUESTIONS_PER_PAGE) . '</a>'; } if ($paging) { $paging = substr($paging, 0, strrpos($paging, '</div>')); $paging .= "<br />{$showall}</div>"; } else { $paging = "<div class='paging'>{$showall}</div>"; } } echo $paging; if ($caneditall || $canmoveall || $canuseall) { echo '<a href="javascript:select_all_in(\'TABLE\',null,\'categoryquestions\');">' . $strselectall . '</a> /' . ' <a href="javascript:deselect_all_in(\'TABLE\',null,\'categoryquestions\');">' . $strselectnone . '</a>'; echo '<br />'; echo '<strong> ' . get_string('withselected', 'quiz') . ':</strong><br />'; if (function_exists('module_specific_buttons')) { echo module_specific_buttons($cm->id); } // print delete and move selected question if ($caneditall) { echo '<input type="submit" name="deleteselected" value="' . $strdelete . "\" />\n"; } if ($canmoveall && count($addcontexts)) { echo '<input type="submit" name="move" value="' . get_string('moveto', 'quiz') . "\" />\n"; question_category_select_menu($addcontexts, false, 0, "{$category->id},{$category->contextid}"); } if (function_exists('module_specific_controls') && $canuseall) { echo module_specific_controls($totalnumber, $recurse, $category, $cm->id); } } echo '</fieldset>'; echo "</form>\n"; }
/** * @param object $quiz the quiz settings * @param object $question the question * @param bool $label if true, show the preview question label after the icon * @return the HTML for a preview question icon. */ function quiz_question_preview_button($quiz, $question, $label = false) { global $CFG, $OUTPUT; if (!question_has_capability_on($question, 'use', $question->category)) { return ''; } $url = quiz_question_preview_url($quiz, $question); // Do we want a label? $strpreviewlabel = ''; if ($label) { $strpreviewlabel = get_string('preview', 'quiz'); } // Build the icon. $strpreviewquestion = get_string('previewquestion', 'quiz'); $image = $OUTPUT->pix_icon('t/preview', $strpreviewquestion); $action = new popup_action('click', $url, 'questionpreview', question_preview_popup_params()); return $OUTPUT->action_link($url, $image, $action, array('title' => $strpreviewquestion)); }
/** * Prints a list of quiz questions for the edit.php main view for edit * ($reordertool = false) and order and paging ($reordertool = true) tabs * * @return int sum of maximum grades * @param object $quiz This is not the standard quiz object used elsewhere but * it contains the quiz layout in $quiz->questions and the grades in * $quiz->grades * @param object $pageurl The url of the current page with the parameters required * for links returning to the current page, as a moodle_url object * @param boolean $allowdelete Indicates whether the delete icons should be displayed * @param boolean $reordertool Indicates whether the reorder tool should be displayed * @param boolean $quiz_qbanktool Indicates whether the question bank should be displayed * @param boolean $hasattempts Indicates whether the quiz has attempts */ function quiz_print_question_list($quiz, $pageurl, $allowdelete = true, $reordertool = false, $quiz_qbanktool = false, $hasattempts = false) { global $USER, $CFG, $QTYPES, $DB; $strorder = get_string('order'); $strquestionname = get_string('questionname', 'quiz'); $strgrade = get_string('grade'); $strremove = get_string('remove', 'quiz'); $stredit = get_string('edit'); $strview = get_string('view'); $straction = get_string('action'); $strmove = get_string('move'); $strmoveup = get_string('moveup'); $strmovedown = get_string('movedown'); $strsave = get_string('save', 'quiz'); $strreorderquestions = get_string('reorderquestions', 'quiz'); $strselectall = get_string('selectall', 'quiz'); $strselectnone = get_string('selectnone', 'quiz'); $strtype = get_string('type', 'quiz'); $strpreview = get_string('preview', 'quiz'); if ($quiz->questions) { list($usql, $params) = $DB->get_in_or_equal(explode(',', $quiz->questions)); $questions = $DB->get_records_sql("SELECT q.*,c.contextid\n FROM {question} q,\n {question_categories} c\n WHERE q.id {$usql}\n AND q.category = c.id", $params); } else { $questions = array(); } $layout = quiz_clean_layout($quiz->questions); $order = explode(',', $layout); $lastindex = count($order) - 1; $disabled = ''; $pagingdisabled = ''; if ($hasattempts) { $disabled = 'disabled="disabled"'; } if ($hasattempts || $quiz->shufflequestions) { $pagingdisabled = 'disabled="disabled"'; } $reordercontrolssetdefaultsubmit = '<div style="display:none;">' . '<input type="submit" name="savechanges" value="' . $strreorderquestions . '" ' . $pagingdisabled . ' /></div>'; $reordercontrols1 = '<div class="addnewpagesafterselected">' . '<input type="submit" name="addnewpagesafterselected" value="' . get_string('addnewpagesafterselected', 'quiz') . '" ' . $pagingdisabled . ' /></div>'; $reordercontrols1 .= '<div class="quizdeleteselected">' . '<input type="submit" name="quizdeleteselected" ' . 'onclick="return confirm(\'' . get_string('areyousureremoveselected', 'quiz') . '\');" value="' . get_string('removeselected', 'quiz') . '" ' . $disabled . ' /></div>'; $a = '<input name="moveselectedonpagetop" type="text" size="2" ' . $pagingdisabled . ' />'; $reordercontrols2top = '<div class="moveselectedonpage">' . get_string('moveselectedonpage', 'quiz', $a) . '<input type="submit" name="savechanges" value="' . $strmove . '" ' . $pagingdisabled . ' />' . ' <br /><input type="submit" name="savechanges" value="' . $strreorderquestions . '" /></div>'; $reordercontrols2bottom = '<div class="moveselectedonpage">' . '<input type="submit" name="savechanges" value="' . $strreorderquestions . '" /><br />' . get_string('moveselectedonpage', 'quiz', $a) . '<input type="submit" name="savechanges" value="' . $strmove . '" ' . $pagingdisabled . ' /> ' . '</div>'; $reordercontrols3 = '<a href="javascript:select_all_in(\'FORM\', null, ' . '\'quizquestions\');">' . $strselectall . '</a> /'; $reordercontrols3 .= ' <a href="javascript:deselect_all_in(\'FORM\', ' . 'null, \'quizquestions\');">' . $strselectnone . '</a>'; $reordercontrolstop = '<div class="reordercontrols">' . $reordercontrolssetdefaultsubmit . $reordercontrols1 . $reordercontrols2top . $reordercontrols3 . "</div>"; $reordercontrolsbottom = '<div class="reordercontrols">' . $reordercontrolssetdefaultsubmit . $reordercontrols2bottom . $reordercontrols1 . $reordercontrols3 . "</div>"; if ($reordertool) { echo '<form method="post" action="edit.php" id="quizquestions"><div>'; echo $pageurl->hidden_params_out(); echo '<input type="hidden" name="sesskey" value="' . sesskey() . '" />'; echo $reordercontrolstop; } //the current question ordinal (no descriptions) $qno = 1; //the current question (includes questions and descriptions) $questioncount = 0; //the ordinal of current element in the layout //(includes page breaks, questions and descriptions) $count = 0; //the current page number in iteration $pagecount = 0; $sumgrade = 0; $pageopen = false; $returnurl = $pageurl->out(); $questiontotalcount = count($order); foreach ($order as $i => $qnum) { $reordercheckbox = ''; $reordercheckboxlabel = ''; $reordercheckboxlabelclose = ''; if ($qnum && empty($questions[$qnum])) { continue; } // If the questiontype is missing change the question type if ($qnum && !array_key_exists($questions[$qnum]->qtype, $QTYPES)) { $questions[$qnum]->qtype = 'missingtype'; } $deletex = "delete.gif"; if ($qnum != 0 || $qnum == 0 && !$pageopen) { //this is either a question or a page break after another // (no page is currently open) if (!$pageopen) { //if no page is open, start display of a page $pagecount++; echo '<div class="quizpage"><span class="pagetitle">' . get_string('page') . ' ' . $pagecount . '</span><div class="pagecontent">'; $pageopen = true; } if ($qnum == 0 && $i < $questiontotalcount) { // This is the second successive page break. Tell the user the page is empty. echo '<div class="pagestatus">'; print_string('noquestionsonpage', 'quiz'); echo '</div>'; if ($allowdelete && !$quiz->questionsperpage) { echo '<div class="quizpagedelete">'; echo '<a title="' . get_string('removeemptypage', 'quiz') . '" href="' . $pageurl->out_action(array('deleteemptypage' => $i - 1)) . '"><img src="' . $CFG->pixpath . '/t/delete.gif" ' . 'class="iconsmall" alt="' . $strremove . '" /></a>'; echo '</div>'; } } if ($qnum != 0) { $question = $questions[$qnum]; $questionparams = array('returnurl' => $returnurl, 'cmid' => $quiz->cmid, 'id' => $question->id); $questionurl = new moodle_url("{$CFG->wwwroot}/question/question.php", $questionparams); $questioncount++; //this is an actual question /* Display question start */ ?> <div class="question"> <div class="questioncontainer <?php echo $question->qtype; ?> "> <div class="qnum"> <?php $reordercheckbox = ''; $reordercheckboxlabel = ''; $reordercheckboxlabelclose = ''; if ($reordertool) { $reordercheckbox = '<input type="checkbox" name="s' . $question->id . '" id="s' . $question->id . '" />'; $reordercheckboxlabel = '<label for="s' . $question->id . '">'; $reordercheckboxlabelclose = '</label>'; } if (!$quiz->shufflequestions) { // Print and increment question number $questioncountstring = ''; if ($questioncount > 999 || $reordertool && $questioncount > 99) { $questioncountstring = "{$reordercheckboxlabel}<small>{$questioncount}</small>" . $reordercheckboxlabelclose . $reordercheckbox; } else { $questioncountstring = $reordercheckboxlabel . $questioncount . $reordercheckboxlabelclose . $reordercheckbox; } echo $questioncountstring; $qno += $question->length; } else { echo "{$reordercheckboxlabel} ? {$reordercheckboxlabelclose}" . " {$reordercheckbox}"; } ?> </div> <div class="content"> <div class="questioncontrols"> <?php if ($count != 0) { if (!$hasattempts) { $upbuttonclass = ''; if ($count >= $lastindex - 1) { $upbuttonclass = 'upwithoutdown'; } echo "<a title=\"{$strmoveup}\" href=\"" . $pageurl->out_action(array('up' => $question->id)) . "\"><img\n src=\"{$CFG->pixpath}/t/up.gif\" class=\"iconsmall\n {$upbuttonclass}\" alt=\"{$strmoveup}\" /></a>"; } } if ($count < $lastindex - 1) { if (!$hasattempts) { echo "<a title=\"{$strmovedown}\" href=\"" . $pageurl->out_action(array('down' => $question->id)) . "\"><img\n src=\"{$CFG->pixpath}/t/down.gif\" class=\"iconsmall\"" . " alt=\"{$strmovedown}\" /></a>"; } } if ($allowdelete && question_has_capability_on($question, 'use', $question->category)) { // remove from quiz, not question delete. if (!$hasattempts) { echo "<a title=\"{$strremove}\" href=\"" . $pageurl->out_action(array('remove' => $question->id)) . "\">\n <img src=\"{$CFG->pixpath}/t/delete.gif\" " . "class=\"iconsmall\" alt=\"{$strremove}\" /></a>"; } } ?> </div><?php if ($question->qtype != 'description' && !$reordertool) { ?> <div class="points"> <form method="post" action="edit.php"><div> <fieldset class="invisiblefieldset" style="display: block;"> <label for="<?php echo "inputq{$question->id}"; ?> "><?php echo $strgrade; ?> </label>:<br /> <input type="hidden" name="sesskey" value="<?php echo sesskey(); ?> " /> <?php echo $pageurl->hidden_params_out(); ?> <input type="hidden" name="savechanges" value="save" /> <?php echo '<input type="text" name="g' . $question->id . '" id="inputq' . $question->id . '" size="' . ($quiz->decimalpoints + 2) . '" value="' . (0 + $quiz->grades[$qnum]) . '" tabindex="' . ($lastindex + $qno) . '" />'; ?> <input type="submit" class="pointssubmitbutton" value="<?php echo $strsave; ?> " /> </fieldset> <?php if ($question->qtype == 'random') { echo '<a href="' . $questionurl->out() . '" class="configurerandomquestion">' . get_string("configurerandomquestion", "quiz") . '</a>'; } ?> </div> </form> </div> <?php } else { if ($reordertool) { if ($qnum) { ?> <div class="qorder"> <?php echo '<input type="text" name="o' . $question->id . '" size="2" value="' . (10 * $count + 10) . '" tabindex="' . ($lastindex + $qno) . '" />'; ?> <!-- <input type="submit" class="pointssubmitbutton" value="<?php echo $strsave; ?> " /> --> </div> <?php } } } ?> <div class="questioncontentcontainer"> <?php if ($question->qtype == 'random') { // it is a random question if (!$reordertool) { quiz_print_randomquestion($question, $pageurl, $quiz, $quiz_qbanktool); } else { quiz_print_randomquestion_reordertool($question, $pageurl, $quiz); } } else { // it is a single question if (!$reordertool) { quiz_print_singlequestion($question, $returnurl, $quiz); } else { quiz_print_singlequestion_reordertool($question, $returnurl, $quiz); } } ?> </div> </div> </div> </div> <?php /* Display question end */ $count++; $sumgrade += $quiz->grades[$qnum]; } } //a page break: end the existing page. if ($qnum == 0) { if ($pageopen) { if (!$reordertool && !($quiz->shufflequestions && $i < $questiontotalcount - 1)) { quiz_print_pagecontrols($quiz, $pageurl, $pagecount, $hasattempts); } else { if ($i < $questiontotalcount - 1) { //do not include the last page break for reordering //to avoid creating a new extra page in the end echo '<input type="hidden" name="opg' . $pagecount . '" size="2" value="' . (10 * $count + 10) . '" />'; } } echo "</div></div>"; if (!$reordertool && !$quiz->shufflequestions) { echo "<div class=\"addpage\">"; print_single_button($pageurl->out(true), array('cmid' => $quiz->cmid, 'courseid' => $quiz->course, 'addpage' => $count, 'sesskey' => sesskey()), get_string('addpagehere', 'quiz'), 'get', '_self', false, '', $hasattempts); echo "</div>"; } $pageopen = false; $count++; } } } if ($reordertool) { echo $reordercontrolsbottom; echo '</div></form>'; } return $sumgrade; }
/** * Verify that the question exists, and the user has permission to use it. * @param object $quiz the quiz settings. * @param int $slot which question in the quiz to test. * @return bool whether the user can use this question. */ function quiz_has_question_use($quiz, $slot) { global $DB; $question = $DB->get_record_sql("\n SELECT q.*\n FROM {quiz_slots} slot\n JOIN {question} q ON q.id = slot.questionid\n WHERE slot.quizid = ? AND slot.slot = ?", array($quiz->id, $slot)); if (!$question) { return false; } return question_has_capability_on($question, 'use'); }
/** * Get a link to an edit icon for this question, if the current user is allowed * to edit it. * * @param object $question the question object. * @param object $cmoptions the options from the module. If $cmoptions->thispageurl is set * then the link will be to edit the question in this browser window, then return to * $cmoptions->thispageurl. Otherwise the link will be to edit in a popup. * @return string the HTML of the link, or nothing it the currenty user is not allowed to edit. */ function get_question_edit_link($question, $cmoptions, $options) { global $CFG, $OUTPUT; /// Is this user allowed to edit this question? if (!empty($options->noeditlink) || !question_has_capability_on($question, 'edit')) { return ''; } /// Work out the right URL. $linkurl = '/question/question.php?id=' . $question->id; if (!empty($cmoptions->cmid)) { $linkurl .= '&cmid=' . $cmoptions->cmid; } else { if (!empty($cmoptions->course)) { $linkurl .= '&courseid=' . $cmoptions->course; } else { print_error('missingcourseorcmidtolink', 'question'); } } /// Work out the contents of the link. $stredit = get_string('edit'); $linktext = '<img src="' . $OUTPUT->old_icon_url('t/edit') . '" alt="' . $stredit . '" />'; if (!empty($cmoptions->thispageurl)) { /// The module allow editing in the same window, print an ordinary link. return '<a href="' . $CFG->wwwroot . $linkurl . '&returnurl=' . urlencode($cmoptions->thispageurl) . '" title="' . $stredit . '">' . $linktext . '</a>'; } else { /// We have to edit in a pop-up. $link = html_link::make($linkurl . '&inpopup=1', $linktext); $link->add_action(new popup_action('click', $link->url, 'editquestion')); $link->title = $stredit; return $OUTPUT->link($link); } }
/** * Wrapper that the correct mod_quiz_display_options for this quiz at the * moment. * * @param bool $reviewing true for review page, else attempt page. * @param int $slot which question is being displayed. * @param moodle_url $thispageurl to return to after the editing form is * submitted or cancelled. If null, no edit link will be generated. * * @return question_display_options the render options for this user on this * attempt, with extra info to generate an edit link, if applicable. */ public function get_display_options_with_edit_link($reviewing, $slot, $thispageurl) { $options = clone $this->get_display_options($reviewing); if (!$thispageurl) { return $options; } if (!($reviewing || $this->is_preview())) { return $options; } $question = $this->quba->get_question($slot); if (!question_has_capability_on($question, 'edit', $question->category)) { return $options; } $options->editquestionparams['cmid'] = $this->get_cmid(); $options->editquestionparams['returnurl'] = $thispageurl; return $options; }
question_require_capability_on($question, 'move'); } else { $question->formoptions->canedit = question_has_capability_on($question, 'edit'); $question->formoptions->canmove = $addpermission && question_has_capability_on($question, 'move'); $question->formoptions->cansaveasnew = $addpermission && (question_has_capability_on($question, 'view') || $question->formoptions->canedit); $question->formoptions->repeatelements = $question->formoptions->canedit || $question->formoptions->cansaveasnew; $formeditable = $question->formoptions->canedit || $question->formoptions->cansaveasnew || $question->formoptions->canmove; $question->formoptions->movecontext = false; if (!$formeditable) { question_require_capability_on($question, 'view'); } } } else { // creating a new question $question->formoptions->canedit = question_has_capability_on($question, 'edit'); $question->formoptions->canmove = question_has_capability_on($question, 'move') && $addpermission; $question->formoptions->cansaveasnew = false; $question->formoptions->repeatelements = true; $question->formoptions->movecontext = false; $formeditable = true; require_capability('moodle/question:add', $categorycontext); } $question->formoptions->mustbeusable = (bool) $appendqnumstring; // Validate the question type. $PAGE->set_pagetype('question-type-' . $question->qtype); // Create the question editing form. if ($wizardnow !== '' && !$movecontext) { $mform = $qtypeobj->next_wizard_form('question.php', $question, $wizardnow, $formeditable); } else { $mform = $qtypeobj->create_editing_form('question.php', $question, $category, $contexts, $formeditable); }
/** * @param object $quiz the quiz * @param object $question the question * @return the HTML for a preview question icon. */ function quiz_question_preview_button($quiz, $question) { global $CFG, $COURSE; if (!question_has_capability_on($question, 'use', $question->category)) { return ''; } $strpreview = get_string('previewquestion', 'quiz'); $quizorcourseid = $quiz->id ? '&quizid=' . $quiz->id : '&courseid=' . $COURSE->id; return link_to_popup_window('/question/preview.php?id=' . $question->id . $quizorcourseid, 'questionpreview', "<img src=\"{$CFG->pixpath}/t/preview.gif\" class=\"iconsmall\" alt=\"{$strpreview}\" />", 0, 0, $strpreview, QUESTION_PREVIEW_POPUP_OPTIONS, true); }
/** * Make some questions and add them to the quiz. * * @param int $courseid * @return stdClass */ public function make_question($courseid) { $context = context_course::instance($courseid); $defaultcategory = question_make_default_categories(array($context)); $questioncategoryid = $defaultcategory->id; global $USER, $DB; // Robbed from question/question.php. $question = new stdClass(); $question->category = $questioncategoryid; $question->qtype = 'essay'; $question->createdby = $USER->id; $question->formoptions = new stdClass(); $question->formoptions->canedit = question_has_capability_on($question, 'edit'); $params = array('id' => $question->category); if (!($category = $DB->get_record('question_categories', $params))) { print_error('categorydoesnotexist', 'question'); } $categorycontext = context::instance_by_id($category->contextid); $addpermission = has_capability('moodle/question:add', $categorycontext); $question->formoptions->canmove = question_has_capability_on($question, 'move') && $addpermission; $question->formoptions->cansaveasnew = false; $question->formoptions->repeatelements = true; $question->formoptions->movecontext = false; $question->formoptions->mustbeusable = 0; $question->errors = array(); $qtypeobj = question_bank::get_qtype('essay'); $fromform = new stdClass(); $fromform->category = $questioncategoryid; // Slash separated. $fromform->name = ''; $fromform->parent = ''; $fromform->penalty = ''; $fromform->questiontext['text'] = ''; $fromform->questiontext['format'] = 1; $fromform->responseformat = 'editor'; $fromform->responsefieldlines = 5; $fromform->attachments = 0; $fromform->graderinfo['text'] = ''; $fromform->graderinfo['format'] = ''; return $qtypeobj->save_question($question, $fromform); }
/** * Do the export * For most types this should not need to be overrided * @return boolean success */ function exportprocess() { global $CFG; // create a directory for the exports (if not already existing) if (!($export_dir = make_upload_directory($this->question_get_export_dir()))) { error(get_string('cannotcreatepath', 'quiz', $export_dir)); } $path = $CFG->dataroot . '/' . $this->question_get_export_dir(); // get the questions (from database) in this category // only get q's with no parents (no cloze subquestions specifically) if ($this->category) { $questions = get_questions_category($this->category, true); } else { $questions = $this->questions; } notify(get_string('exportingquestions', 'quiz')); $count = 0; // results are first written into string (and then to a file) // so create/initialize the string here $expout = ""; // track which category questions are in // if it changes we will record the category change in the output // file if selected. 0 means that it will get printed before the 1st question $trackcategory = 0; // iterate through questions foreach ($questions as $question) { // do not export hidden questions if (!empty($question->hidden)) { continue; } // do not export random questions if ($question->qtype == RANDOM) { continue; } // check if we need to record category change if ($this->cattofile) { if ($question->category != $trackcategory) { $trackcategory = $question->category; $categoryname = $this->get_category_path($trackcategory, '/', $this->contexttofile); // create 'dummy' question for category export $dummyquestion = new object(); $dummyquestion->qtype = 'category'; $dummyquestion->category = $categoryname; $dummyquestion->name = "switch category to {$categoryname}"; $dummyquestion->id = 0; $dummyquestion->questiontextformat = ''; $expout .= $this->writequestion($dummyquestion) . "\n"; } } // export the question displaying message $count++; echo "<hr /><p><b>{$count}</b>. " . $this->format_question_text($question) . "</p>"; if (question_has_capability_on($question, 'view', $question->category)) { $expout .= $this->writequestion($question) . "\n"; } } // continue path for following error checks $course = $this->course; $continuepath = "{$CFG->wwwroot}/question/export.php?courseid={$course->id}"; // did we actually process anything if ($count == 0) { print_error('noquestions', 'quiz', $continuepath); } // final pre-process on exported data $expout = $this->presave_process($expout); // write file $filepath = $path . "/" . $this->filename . $this->export_file_extension(); if (!($fh = fopen($filepath, "w"))) { print_error('cannotopen', 'quiz', $continuepath, $filepath); } if (!fwrite($fh, $expout, strlen($expout))) { print_error('cannotwrite', 'quiz', $continuepath, $filepath); } fclose($fh); return true; }
/** * Prints a list of quiz questions for the edit.php main view for edit * ($reordertool = false) and order and paging ($reordertool = true) tabs * * @return int sum of maximum grades * @param object $quiz This is not the standard quiz object used elsewhere but * it contains the quiz layout in $quiz->questions and the grades in * $quiz->grades * @param object $pageurl The url of the current page with the parameters required * for links returning to the current page, as a moodle_url object * @param bool $allowdelete Indicates whether the delete icons should be displayed * @param bool $reordertool Indicates whether the reorder tool should be displayed * @param bool $quiz_qbanktool Indicates whether the question bank should be displayed * @param bool $hasattempts Indicates whether the quiz has attempts */ function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool, $quiz_qbanktool, $hasattempts, $defaultcategoryobj) { global $CFG, $DB, $OUTPUT; $strorder = get_string('order'); $strquestionname = get_string('questionname', 'quiz'); $strgrade = get_string('grade'); $strremove = get_string('remove', 'quiz'); $stredit = get_string('edit'); $strview = get_string('view'); $straction = get_string('action'); $strmove = get_string('move'); $strmoveup = get_string('moveup'); $strmovedown = get_string('movedown'); $strsave = get_string('save', 'quiz'); $strreorderquestions = get_string('reorderquestions', 'quiz'); $strselectall = get_string('selectall', 'quiz'); $strselectnone = get_string('selectnone', 'quiz'); $strtype = get_string('type', 'quiz'); $strpreview = get_string('preview', 'quiz'); if ($quiz->questions) { list($usql, $params) = $DB->get_in_or_equal(explode(',', $quiz->questions)); $params[] = $quiz->id; $questions = $DB->get_records_sql("SELECT q.*, qc.contextid, qqi.grade as maxmark FROM {question} q JOIN {question_categories} qc ON qc.id = q.category JOIN {quiz_question_instances} qqi ON qqi.question = q.id WHERE q.id $usql AND qqi.quiz = ?", $params); } else { $questions = array(); } $layout = quiz_clean_layout($quiz->questions); $order = explode(',', $layout); $lastindex = count($order) - 1; $disabled = ''; $pagingdisabled = ''; if ($hasattempts) { $disabled = 'disabled="disabled"'; } if ($hasattempts || $quiz->shufflequestions) { $pagingdisabled = 'disabled="disabled"'; } $reordercontrolssetdefaultsubmit = '<div style="display:none;">' . '<input type="submit" name="savechanges" value="' . $strreorderquestions . '" ' . $pagingdisabled . ' /></div>'; $reordercontrols1 = '<div class="addnewpagesafterselected">' . '<input type="submit" name="addnewpagesafterselected" value="' . get_string('addnewpagesafterselected', 'quiz') . '" ' . $pagingdisabled . ' /></div>'; $reordercontrols1 .= '<div class="quizdeleteselected">' . '<input type="submit" name="quizdeleteselected" ' . 'onclick="return confirm(\'' . get_string('areyousureremoveselected', 'quiz') . '\');" value="' . get_string('removeselected', 'quiz') . '" ' . $disabled . ' /></div>'; $a = '<input name="moveselectedonpagetop" type="text" size="2" ' . $pagingdisabled . ' />'; $b = '<input name="moveselectedonpagebottom" type="text" size="2" ' . $pagingdisabled . ' />'; $reordercontrols2top = '<div class="moveselectedonpage">' . get_string('moveselectedonpage', 'quiz', $a) . '<input type="submit" name="savechanges" value="' . $strmove . '" ' . $pagingdisabled . ' />' . ' <br /><input type="submit" name="savechanges" value="' . $strreorderquestions . '" /></div>'; $reordercontrols2bottom = '<div class="moveselectedonpage">' . '<input type="submit" name="savechanges" value="' . $strreorderquestions . '" /><br />' . get_string('moveselectedonpage', 'quiz', $b) . '<input type="submit" name="savechanges" value="' . $strmove . '" ' . $pagingdisabled . ' /> ' . '</div>'; $reordercontrols3 = '<a href="javascript:select_all_in(\'FORM\', null, ' . '\'quizquestions\');">' . $strselectall . '</a> /'; $reordercontrols3.= ' <a href="javascript:deselect_all_in(\'FORM\', ' . 'null, \'quizquestions\');">' . $strselectnone . '</a>'; $reordercontrolstop = '<div class="reordercontrols">' . $reordercontrolssetdefaultsubmit . $reordercontrols1 . $reordercontrols2top . $reordercontrols3 . "</div>"; $reordercontrolsbottom = '<div class="reordercontrols">' . $reordercontrolssetdefaultsubmit . $reordercontrols2bottom . $reordercontrols1 . $reordercontrols3 . "</div>"; if ($reordertool) { echo '<form method="post" action="edit.php" id="quizquestions"><div>'; echo html_writer::input_hidden_params($pageurl); echo '<input type="hidden" name="sesskey" value="' . sesskey() . '" />'; echo $reordercontrolstop; } //the current question ordinal (no descriptions) $qno = 1; //the current question (includes questions and descriptions) $questioncount = 0; //the current page number in iteration $pagecount = 0; $pageopen = false; $returnurl = $pageurl->out_as_local_url(false); $questiontotalcount = count($order); foreach ($order as $count => $qnum) { $reordercheckbox = ''; $reordercheckboxlabel = ''; $reordercheckboxlabelclose = ''; // If the questiontype is missing change the question type if ($qnum && !array_key_exists($qnum, $questions)) { $fakequestion = new stdClass(); $fakequestion->id = $qnum; $fakequestion->category = 0; $fakequestion->qtype = 'missingtype'; $fakequestion->name = get_string('missingquestion', 'quiz'); $fakequestion->questiontext = ' '; $fakequestion->questiontextformat = FORMAT_HTML; $fakequestion->length = 1; $questions[$qnum] = $fakequestion; $quiz->grades[$qnum] = 0; } else if ($qnum && !question_bank::qtype_exists($questions[$qnum]->qtype)) { $questions[$qnum]->qtype = 'missingtype'; } if ($qnum != 0 || ($qnum == 0 && !$pageopen)) { //this is either a question or a page break after another // (no page is currently open) if (!$pageopen) { //if no page is open, start display of a page $pagecount++; echo '<div class="quizpage"><span class="pagetitle">' . get_string('page') . ' ' . $pagecount . '</span><div class="pagecontent">'; $pageopen = true; } if ($qnum == 0 && $count < $questiontotalcount) { // This is the second successive page break. Tell the user the page is empty. echo '<div class="pagestatus">'; print_string('noquestionsonpage', 'quiz'); echo '</div>'; if ($allowdelete) { echo '<div class="quizpagedelete">'; echo $OUTPUT->action_icon($pageurl->out(true, array('deleteemptypage' => $count - 1, 'sesskey'=>sesskey())), new pix_icon('t/delete', $strremove), new component_action('click', 'M.core_scroll_manager.save_scroll_action'), array('title' => $strremove)); echo '</div>'; } } if ($qnum != 0) { $question = $questions[$qnum]; $questionparams = array( 'returnurl' => $returnurl, 'cmid' => $quiz->cmid, 'id' => $question->id); $questionurl = new moodle_url('/question/question.php', $questionparams); $questioncount++; //this is an actual question /* Display question start */ ?> <div class="question"> <div class="questioncontainer <?php echo $question->qtype; ?>"> <div class="qnum"> <?php $reordercheckbox = ''; $reordercheckboxlabel = ''; $reordercheckboxlabelclose = ''; if ($reordertool) { $reordercheckbox = '<input type="checkbox" name="s' . $question->id . '" id="s' . $question->id . '" />'; $reordercheckboxlabel = '<label for="s' . $question->id . '">'; $reordercheckboxlabelclose = '</label>'; } if ($question->length == 0) { $qnodisplay = get_string('infoshort', 'quiz'); } else if ($quiz->shufflequestions) { $qnodisplay = '?'; } else { if ($qno > 999 || ($reordertool && $qno > 99)) { $qnodisplay = html_writer::tag('small', $qno); } else { $qnodisplay = $qno; } $qno += $question->length; } echo $reordercheckboxlabel . $qnodisplay . $reordercheckboxlabelclose . $reordercheckbox; ?> </div> <div class="content"> <div class="questioncontrols"> <?php if ($count != 0) { if (!$hasattempts) { $upbuttonclass = ''; if ($count >= $lastindex - 1) { $upbuttonclass = 'upwithoutdown'; } echo $OUTPUT->action_icon($pageurl->out(true, array('up' => $question->id, 'sesskey'=>sesskey())), new pix_icon('t/up', $strmoveup), new component_action('click', 'M.core_scroll_manager.save_scroll_action'), array('title' => $strmoveup)); } } if ($count < $lastindex - 1) { if (!$hasattempts) { echo $OUTPUT->action_icon($pageurl->out(true, array('down' => $question->id, 'sesskey'=>sesskey())), new pix_icon('t/down', $strmovedown), new component_action('click', 'M.core_scroll_manager.save_scroll_action'), array('title' => $strmovedown)); } } if ($allowdelete && ($question->qtype == 'missingtype' || question_has_capability_on($question, 'use', $question->category))) { // remove from quiz, not question delete. if (!$hasattempts) { echo $OUTPUT->action_icon($pageurl->out(true, array('remove' => $question->id, 'sesskey'=>sesskey())), new pix_icon('t/delete', $strremove), new component_action('click', 'M.core_scroll_manager.save_scroll_action'), array('title' => $strremove)); } } ?> </div><?php if (!in_array($question->qtype, array('description', 'missingtype')) && !$reordertool) { ?> <div class="points"> <form method="post" action="edit.php" class="quizsavegradesform"><div> <fieldset class="invisiblefieldset" style="display: block;"> <label for="<?php echo "inputq$question->id" ?>"><?php echo $strgrade; ?></label>:<br /> <input type="hidden" name="sesskey" value="<?php echo sesskey() ?>" /> <?php echo html_writer::input_hidden_params($pageurl); ?> <input type="hidden" name="savechanges" value="save" /> <?php echo '<input type="text" name="g' . $question->id . '" id="inputq' . $question->id . '" size="' . ($quiz->decimalpoints + 2) . '" value="' . (0 + $quiz->grades[$qnum]) . '" tabindex="' . ($lastindex + $qno) . '" />'; ?> <input type="submit" class="pointssubmitbutton" value="<?php echo $strsave; ?>" /> </fieldset> <?php if ($question->qtype == 'random') { echo '<a href="' . $questionurl->out() . '" class="configurerandomquestion">' . get_string("configurerandomquestion", "quiz") . '</a>'; } ?> </div> </form> </div> <?php } else if ($reordertool) { if ($qnum) { ?> <div class="qorder"> <?php echo '<input type="text" name="o' . $question->id . '" size="2" value="' . (10*$count + 10) . '" tabindex="' . ($lastindex + $qno) . '" />'; ?> </div> <?php } } ?> <div class="questioncontentcontainer"> <?php if ($question->qtype == 'random') { // it is a random question if (!$reordertool) { quiz_print_randomquestion($question, $pageurl, $quiz, $quiz_qbanktool); } else { quiz_print_randomquestion_reordertool($question, $pageurl, $quiz); } } else { // it is a single question if (!$reordertool) { quiz_print_singlequestion($question, $returnurl, $quiz); } else { quiz_print_singlequestion_reordertool($question, $returnurl, $quiz); } } ?> </div> </div> </div> </div> <?php } } //a page break: end the existing page. if ($qnum == 0) { if ($pageopen) { if (!$reordertool && !($quiz->shufflequestions && $count < $questiontotalcount - 1)) { quiz_print_pagecontrols($quiz, $pageurl, $pagecount, $hasattempts, $defaultcategoryobj); } else if ($count < $questiontotalcount - 1) { //do not include the last page break for reordering //to avoid creating a new extra page in the end echo '<input type="hidden" name="opg' . $pagecount . '" size="2" value="' . (10*$count + 10) . '" />'; } echo "</div></div>"; if (!$reordertool && !$quiz->shufflequestions) { echo $OUTPUT->container_start('addpage'); $url = new moodle_url($pageurl->out_omit_querystring(), array('cmid' => $quiz->cmid, 'courseid' => $quiz->course, 'addpage' => $count, 'sesskey' => sesskey())); echo $OUTPUT->single_button($url, get_string('addpagehere', 'quiz'), 'post', array('disabled' => $hasattempts, 'actions' => array(new component_action('click', 'M.core_scroll_manager.save_scroll_action')))); echo $OUTPUT->container_end(); } $pageopen = false; $count++; } } } if ($reordertool) { echo $reordercontrolsbottom; echo '</div></form>'; } }
function display($quiz, $cm, $course) { /// This function just displays the report global $CFG, $SESSION, $QTYPES; $strnoattempts = get_string('noattempts', 'quiz'); /// Only print headers if not asked to download data $download = optional_param('download', NULL); if (!$download) { $this->print_header_and_tabs($cm, $course, $quiz, $reportmode = "analysis"); } /// Construct the table for this particular report if (!$quiz->questions) { print_heading($strnoattempts); return true; } /// Check to see if groups are being used in this quiz $currentgroup = groups_get_activity_group($cm, true); if ($groupmode = groups_get_activity_groupmode($cm)) { // Groups are being used if (!$download) { groups_print_activity_menu($cm, "report.php?id={$cm->id}&mode=analysis"); } } // set Table and Analysis stats options if (!isset($SESSION->quiz_analysis_table)) { $SESSION->quiz_analysis_table = array('attemptselection' => 0, 'lowmarklimit' => 0, 'pagesize' => QUIZ_REPORT_DEFAULT_PAGE_SIZE); } foreach ($SESSION->quiz_analysis_table as $option => $value) { $urlparam = optional_param($option, NULL, PARAM_INT); if ($urlparam === NULL) { ${$option} = $value; } else { ${$option} = $SESSION->quiz_analysis_table[$option] = $urlparam; } } if (!isset($pagesize) || (int) $pagesize < 1) { $pagesize = QUIZ_REPORT_DEFAULT_PAGE_SIZE; } $scorelimit = $quiz->sumgrades * $lowmarklimit / 100; // ULPGC ecastro DEBUG this is here to allow for different SQL to select attempts switch ($attemptselection) { case QUIZ_ALLATTEMPTS: $limit = ''; $group = ''; break; case QUIZ_HIGHESTATTEMPT: $limit = ', max(qa.sumgrades) '; $group = ' GROUP BY qa.userid '; break; case QUIZ_FIRSTATTEMPT: $limit = ', min(qa.timemodified) '; $group = ' GROUP BY qa.userid '; break; case QUIZ_LASTATTEMPT: $limit = ', max(qa.timemodified) '; $group = ' GROUP BY qa.userid '; break; } if ($attemptselection != QUIZ_ALLATTEMPTS) { $sql = 'SELECT qa.userid ' . $limit . 'FROM ' . $CFG->prefix . 'user u LEFT JOIN ' . $CFG->prefix . 'quiz_attempts qa ON u.id = qa.userid ' . 'WHERE qa.quiz = ' . $quiz->id . ' AND qa.preview = 0 ' . $group; $usermax = get_records_sql_menu($sql); } $groupmembers = ''; $groupwhere = ''; //Add this to the SQL to show only group users if ($currentgroup) { $groupmembers = ", {$CFG->prefix}groups_members gm "; $groupwhere = "AND gm.groupid = '{$currentgroup}' AND u.id = gm.userid"; } $sql = 'SELECT qa.* FROM ' . $CFG->prefix . 'quiz_attempts qa, ' . $CFG->prefix . 'user u ' . $groupmembers . 'WHERE u.id = qa.userid AND qa.quiz = ' . $quiz->id . ' AND qa.preview = 0 AND ( qa.sumgrades >= ' . $scorelimit . ' ) ' . $groupwhere; // ^^^^^^ es posible seleccionar aqu TODOS los quizzes, como quiere Jussi, // pero haba que llevar la cuenta ed cada quiz para restaura las preguntas (quizquestions, states) /// Fetch the attempts $attempts = get_records_sql($sql); if (empty($attempts)) { print_heading(get_string('nothingtodisplay')); $this->print_options_form($quiz, $cm, $attemptselection, $lowmarklimit, $pagesize); return true; } /// Here we rewiew all attempts and record data to construct the table $questions = array(); $statstable = array(); $questionarray = array(); foreach ($attempts as $attempt) { $questionarray[] = quiz_questions_in_quiz($attempt->layout); } $questionlist = quiz_questions_in_quiz(implode(",", $questionarray)); $questionarray = array_unique(explode(",", $questionlist)); $questionlist = implode(",", $questionarray); unset($questionarray); foreach ($attempts as $attempt) { switch ($attemptselection) { case QUIZ_ALLATTEMPTS: $userscore = 0; // can be anything, not used break; case QUIZ_HIGHESTATTEMPT: $userscore = $attempt->sumgrades; break; case QUIZ_FIRSTATTEMPT: $userscore = $attempt->timemodified; break; case QUIZ_LASTATTEMPT: $userscore = $attempt->timemodified; break; } if ($attemptselection == QUIZ_ALLATTEMPTS || $userscore == $usermax[$attempt->userid]) { $sql = "SELECT q.*, i.grade AS maxgrade, i.id AS instance" . " FROM {$CFG->prefix}question q," . " {$CFG->prefix}quiz_question_instances i" . " WHERE i.quiz = '{$quiz->id}' AND q.id = i.question" . " AND q.id IN ({$questionlist})"; if (!($quizquestions = get_records_sql($sql))) { error('No questions found'); } // Load the question type specific information if (!get_question_options($quizquestions)) { error('Could not load question options'); } // Restore the question sessions to their most recent states // creating new sessions where required if (!($states = get_question_states($quizquestions, $quiz, $attempt))) { error('Could not restore question sessions'); } $numbers = explode(',', $questionlist); $statsrow = array(); foreach ($numbers as $i) { if (!isset($quizquestions[$i]) or !isset($states[$i])) { continue; } $qtype = $quizquestions[$i]->qtype == 'random' ? $states[$i]->options->question->qtype : $quizquestions[$i]->qtype; $q = get_question_responses($quizquestions[$i], $states[$i]); if (empty($q)) { continue; } $qid = $q->id; if (!isset($questions[$qid])) { $questions[$qid]['id'] = $qid; $questions[$qid]['qname'] = $quizquestions[$i]->name; foreach ($q->responses as $answer => $r) { $r->count = 0; $questions[$qid]['responses'][$answer] = $r->answer; $questions[$qid]['rcounts'][$answer] = 0; $questions[$qid]['credits'][$answer] = $r->credit; $statsrow[$qid] = 0; } } $responses = get_question_actual_response($quizquestions[$i], $states[$i]); foreach ($responses as $resp) { if ($resp) { if ($key = array_search($resp, $questions[$qid]['responses'])) { $questions[$qid]['rcounts'][$key]++; } else { $test = new stdClass(); $test->responses = $QTYPES[$quizquestions[$i]->qtype]->get_correct_responses($quizquestions[$i], $states[$i]); if ($key = $QTYPES[$quizquestions[$i]->qtype]->check_response($quizquestions[$i], $states[$i], $test)) { $questions[$qid]['rcounts'][$key]++; } else { $questions[$qid]['responses'][] = $resp; $questions[$qid]['rcounts'][] = 1; $questions[$qid]['credits'][] = 0; } } } } $statsrow[$qid] = get_question_fraction_grade($quizquestions[$i], $states[$i]); } $attemptscores[$attempt->id] = $attempt->sumgrades; $statstable[$attempt->id] = $statsrow; } } // Statistics Data table built unset($attempts); unset($quizquestions); unset($states); // now calculate statistics and set the values in the $questions array $top = max($attemptscores); $bottom = min($attemptscores); $gap = ($top - $bottom) / 3; $top -= $gap; $bottom += $gap; foreach ($questions as $qid => $q) { $questions[$qid] = $this->report_question_stats($q, $attemptscores, $statstable, $top, $bottom); } unset($attemptscores); unset($statstable); /// Now check if asked download of data if ($download = optional_param('download', NULL)) { $filename = clean_filename("{$course->shortname} " . format_string($quiz->name, true)); switch ($download) { case "Excel": $this->Export_Excel($questions, $filename); break; case "ODS": $this->Export_ODS($questions, $filename); break; case "CSV": $this->Export_CSV($questions, $filename); break; } } /// Construct the table for this particular report $tablecolumns = array('id', 'qname', 'responses', 'credits', 'rcounts', 'rpercent', 'facility', 'qsd', 'disc_index', 'disc_coeff'); $tableheaders = array(get_string('qidtitle', 'quiz_analysis'), get_string('qtexttitle', 'quiz_analysis'), get_string('responsestitle', 'quiz_analysis'), get_string('rfractiontitle', 'quiz_analysis'), get_string('rcounttitle', 'quiz_analysis'), get_string('rpercenttitle', 'quiz_analysis'), get_string('facilitytitle', 'quiz_analysis'), get_string('stddevtitle', 'quiz_analysis'), get_string('dicsindextitle', 'quiz_analysis'), get_string('disccoefftitle', 'quiz_analysis')); $table = new flexible_table('mod-quiz-report-itemanalysis'); $table->define_columns($tablecolumns); $table->define_headers($tableheaders); $table->define_baseurl($CFG->wwwroot . '/mod/quiz/report.php?q=' . $quiz->id . '&mode=analysis'); $table->sortable(true); $table->no_sorting('rpercent'); $table->collapsible(true); $table->initialbars(false); $table->column_class('id', 'numcol'); $table->column_class('credits', 'numcol'); $table->column_class('rcounts', 'numcol'); $table->column_class('rpercent', 'numcol'); $table->column_class('facility', 'numcol'); $table->column_class('qsd', 'numcol'); $table->column_class('disc_index', 'numcol'); $table->column_class('disc_coeff', 'numcol'); $table->column_suppress('id'); $table->column_suppress('qname'); $table->column_suppress('facility'); $table->column_suppress('qsd'); $table->column_suppress('disc_index'); $table->column_suppress('disc_coeff'); $table->set_attribute('cellspacing', '0'); $table->set_attribute('id', 'itemanalysis'); $table->set_attribute('class', 'generaltable generalbox'); // Start working -- this is necessary as soon as the niceties are over $table->setup(); $tablesort = $table->get_sql_sort(); $sorts = explode(",", trim($tablesort)); if ($tablesort and is_array($sorts)) { $sortindex = array(); $sortorder = array(); foreach ($sorts as $sort) { $data = explode(" ", trim($sort)); $sortindex[] = trim($data[0]); $s = trim($data[1]); if ($s == "ASC") { $sortorder[] = SORT_ASC; } else { $sortorder[] = SORT_DESC; } } if (count($sortindex) > 0) { $sortindex[] = "id"; $sortorder[] = SORT_ASC; foreach ($questions as $qid => $row) { $index1[$qid] = $row[$sortindex[0]]; $index2[$qid] = $row[$sortindex[1]]; } array_multisort($index1, $sortorder[0], $index2, $sortorder[1], $questions); } } $format_options = new stdClass(); $format_options->para = false; $format_options->noclean = true; $format_options->newlines = false; // Now it is time to page the data, simply slice the keys in the array $table->pagesize($pagesize, count($questions)); $start = $table->get_page_start(); $pagequestions = array_slice(array_keys($questions), $start, $pagesize); foreach ($pagequestions as $qnum) { $q = $questions[$qnum]; $qid = $q['id']; $question = get_record('question', 'id', $qid); if (question_has_capability_on($question, 'edit') || question_has_capability_on($question, 'view')) { $qnumber = " (" . link_to_popup_window('/question/question.php?id=' . $qid . '&cmid=' . $cm->id, 'editquestion', $qid, 450, 550, get_string('edit'), 'none', true) . ") "; } else { $qnumber = $qid; } $qname = '<div class="qname">' . format_text($question->name . " : ", $question->questiontextformat, $format_options, $quiz->course) . '</div>'; $qicon = print_question_icon($question, true); $qreview = quiz_question_preview_button($quiz, $question); $qtext = format_text($question->questiontext, $question->questiontextformat, $format_options, $quiz->course); $qquestion = $qname . "\n" . $qtext . "\n"; $responses = array(); foreach ($q['responses'] as $aid => $resp) { $response = new stdClass(); if ($q['credits'][$aid] <= 0) { $qclass = 'uncorrect'; } elseif ($q['credits'][$aid] == 1) { $qclass = 'correct'; } else { $qclass = 'partialcorrect'; } $response->credit = '<span class="' . $qclass . '">(' . format_float($q['credits'][$aid], 2) . ') </span>'; $response->text = '<span class="' . $qclass . '">' . format_text($resp, FORMAT_MOODLE, $format_options, $quiz->course) . ' </span>'; $count = $q['rcounts'][$aid] . '/' . $q['count']; $response->rcount = $count; $response->rpercent = '(' . format_float($q['rcounts'][$aid] / $q['count'] * 100, 0) . '%)'; $responses[] = $response; } $facility = format_float($q['facility'] * 100, 0) . "%"; $qsd = format_float($q['qsd'], 3); $di = format_float($q['disc_index'], 2); $dc = format_float($q['disc_coeff'], 2); $response = array_shift($responses); $table->add_data(array($qnumber . "\n<br />" . $qicon . "\n " . $qreview, $qquestion, $response->text, $response->credit, $response->rcount, $response->rpercent, $facility, $qsd, $di, $dc)); foreach ($responses as $response) { $table->add_data(array('', '', $response->text, $response->credit, $response->rcount, $response->rpercent, '', '', '', '')); } } print_heading_with_help(get_string("analysistitle", "quiz_analysis"), "itemanalysis", "quiz"); echo '<div id="tablecontainer">'; $table->print_html(); echo '</div>'; $this->print_options_form($quiz, $cm, $attemptselection, $lowmarklimit, $pagesize); return true; }
/** * Called via pluginfile.php -> question_pluginfile to serve files belonging to * a question in a question_attempt when that attempt is a preview. * * @param object $course course settings object * @param object $context context object * @param string $component the name of the component we are serving files for. * @param string $filearea the name of the file area. * @param int $qubaid the question_usage this image belongs to. * @param int $slot the relevant slot within the usage. * @param array $args the remaining bits of the file path. * @param bool $forcedownload whether the user must be forced to download the file. * @return bool false if file not found, does not return if found - justsend the file */ function question_preview_question_pluginfile($course, $context, $component, $filearea, $qubaid, $slot, $args, $forcedownload) { global $USER, $DB, $CFG; $quba = question_engine::load_questions_usage_by_activity($qubaid); if (!question_has_capability_on($quba->get_question($slot), 'use')) { send_file_not_found(); } $options = new question_display_options(); $options->feedback = question_display_options::VISIBLE; $options->numpartscorrect = question_display_options::VISIBLE; $options->generalfeedback = question_display_options::VISIBLE; $options->rightanswer = question_display_options::VISIBLE; $options->manualcomment = question_display_options::VISIBLE; $options->history = question_display_options::VISIBLE; if (!$quba->check_file_access($slot, $options, $component, $filearea, $args, $forcedownload)) { send_file_not_found(); } $fs = get_file_storage(); $relativepath = implode('/', $args); $fullpath = "/{$context->id}/{$component}/{$filearea}/{$relativepath}"; if (!($file = $fs->get_file_by_hash(sha1($fullpath))) or $file->is_directory()) { send_file_not_found(); } send_stored_file($file, 0, 0, $forcedownload); }
} else { require_login($quiz->course, false, get_coursemodule_from_instance('quiz', $quizid, $quiz->course)); } } if ($maxgrade = get_field('quiz_question_instances', 'grade', 'quiz', $quiz->id, 'question', $id)) { $questions[$id]->maxgrade = $maxgrade; } else { $questions[$id]->maxgrade = $questions[$id]->defaultgrade; } $quiz->id = 0; // just for safety $quiz->questions = $id; if (!($category = get_record("question_categories", "id", $questions[$id]->category))) { error("This question doesn't belong to a valid category!"); } if (!question_has_capability_on($questions[$id], 'use', $questions[$id]->category)) { error("You can't preview these questions!"); } if (isset($COURSE)) { $quiz->course = $COURSE->id; } // Load the question type specific information if (!get_question_options($questions)) { print_error('newattemptfail', 'quiz'); } // Create a dummy quiz attempt // TODO: find out what of the following we really need. What is $attempt // really used for? $timenow = time(); $attempt->quiz = $quiz->id; $attempt->userid = $USER->id;
protected function display_content($question, $rowclasses) { if (!question_has_capability_on($question, 'use')) { return; } // For RTL languages: switch right and left arrows. if (right_to_left()) { $movearrow = 't/removeright'; } else { $movearrow = 't/moveleft'; } $this->print_icon($movearrow, $this->stradd, $this->qbank->add_to_quiz_url($question->id)); }
/** * @param object $quiz the quiz * @param object $question the question * @param boolean $label if true, show the previewquestion label after the icon * @return the HTML for a preview question icon. */ function quiz_question_preview_button($quiz, $question, $label = false) { global $CFG, $COURSE, $OUTPUT; if (!question_has_capability_on($question, 'use', $question->category)) { return ''; } // Minor efficiency saving. Only get strings once, even if there are a lot of icons on one page. static $strpreview = null; static $strpreviewquestion = null; if ($strpreview === null) { $strpreview = get_string('preview', 'quiz'); $strpreviewquestion = get_string('previewquestion', 'quiz'); } // Do we want a label? $strpreviewlabel = ""; if ($label) { $strpreviewlabel = $strpreview; } // Build the icon. $image = new html_image(); $image->src = $OUTPUT->old_icon_url('t/preview'); $image->add_class('iconsmall'); $image->alt = $strpreviewquestion; $link = html_link::make("/question/preview.php?id={$question->id}&quizid={$quiz->id}", $strpreviewlabel); parse_str(QUESTION_PREVIEW_POPUP_OPTIONS, $options); $link->add_action(new popup_action('click', $link->url, 'questionpreview', $options)); $link->title = $strpreviewquestion; return $OUTPUT->link_to_popup($link, $image); }
/** * Do the export * For most types this should not need to be overrided * @return stored_file */ public function exportprocess() { global $CFG, $OUTPUT, $DB, $USER; // get the questions (from database) in this category // only get q's with no parents (no cloze subquestions specifically) if ($this->category) { $questions = get_questions_category($this->category, true); } else { $questions = $this->questions; } $count = 0; // results are first written into string (and then to a file) // so create/initialize the string here $expout = ""; // track which category questions are in // if it changes we will record the category change in the output // file if selected. 0 means that it will get printed before the 1st question $trackcategory = 0; // iterate through questions foreach ($questions as $question) { // used by file api $contextid = $DB->get_field('question_categories', 'contextid', array('id' => $question->category)); $question->contextid = $contextid; // do not export hidden questions if (!empty($question->hidden)) { continue; } // do not export random questions if ($question->qtype == 'random') { continue; } // check if we need to record category change if ($this->cattofile) { if ($question->category != $trackcategory) { $trackcategory = $question->category; $categoryname = $this->get_category_path($trackcategory, $this->contexttofile); // create 'dummy' question for category export $dummyquestion = new stdClass(); $dummyquestion->qtype = 'category'; $dummyquestion->category = $categoryname; $dummyquestion->name = 'Switch category to ' . $categoryname; $dummyquestion->id = 0; $dummyquestion->questiontextformat = ''; $dummyquestion->contextid = 0; $expout .= $this->writequestion($dummyquestion) . "\n"; } } // export the question displaying message $count++; if (question_has_capability_on($question, 'view', $question->category)) { $expout .= $this->writequestion($question, $contextid) . "\n"; } } // continue path for following error checks $course = $this->course; $continuepath = "$CFG->wwwroot/question/export.php?courseid=$course->id"; // did we actually process anything if ($count==0) { print_error('noquestions', 'question', $continuepath); } // final pre-process on exported data $expout = $this->presave_process($expout); return $expout; }
/** * Prints a list of quiz questions in a small layout form with knobs * * @return int sum of maximum grades * @param object $quiz This is not the standard quiz object used elsewhere but * it contains the quiz layout in $quiz->questions and the grades in * $quiz->grades * @param boolean $allowdelete Indicates whether the delete icons should be displayed * @param boolean $showbreaks Indicates whether the page breaks should be displayed * @param boolean $showbreaks Indicates whether the reorder tool should be displayed */ function quiz_print_question_list($quiz, $pageurl, $allowdelete = true, $showbreaks = true, $reordertool = false) { global $USER, $CFG, $QTYPES; $strorder = get_string("order"); $strquestionname = get_string("questionname", "quiz"); $strgrade = get_string("grade"); $strremove = get_string('remove', 'quiz'); $stredit = get_string("edit"); $strview = get_string("view"); $straction = get_string("action"); $strmoveup = get_string("moveup"); $strmovedown = get_string("movedown"); $strsavegrades = get_string("savegrades", "quiz"); $strtype = get_string("type", "quiz"); $strpreview = get_string("preview", "quiz"); if (!$quiz->questions) { echo "<p class=\"quizquestionlistcontrols\">"; print_string("noquestions", "quiz"); echo "</p>"; return 0; } if (!($questions = get_records_sql("SELECT q.*,c.contextid\n FROM {$CFG->prefix}question q,\n {$CFG->prefix}question_categories c\n WHERE q.id in ({$quiz->questions})\n AND q.category = c.id"))) { echo "<p class=\"quizquestionlistcontrols\">"; print_string("noquestions", "quiz"); echo "</p>"; return 0; } $count = 0; $qno = 1; $sumgrade = 0; $order = explode(',', $quiz->questions); $lastindex = count($order) - 1; // If the list does not end with a pagebreak then add it on. if ($order[$lastindex] != 0) { $order[] = 0; $lastindex++; } echo "<form method=\"post\" action=\"edit.php\">"; echo '<fieldset class="invisiblefieldset" style="display: block;">'; echo "<input type=\"hidden\" name=\"sesskey\" value=\"{$USER->sesskey}\" />"; echo $pageurl->hidden_params_out(); echo "<table style=\"width:100%;\">\n"; echo "<tr><th colspan=\"3\" style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">{$strorder}</th>"; echo "<th class=\"header\" scope=\"col\">#</th>"; echo "<th align=\"left\" style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">{$strquestionname}</th>"; echo "<th style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">{$strtype}</th>"; echo "<th style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">{$strgrade}</th>"; echo "<th align=\"center\" style=\"white-space:nowrap;\" class=\"header\" scope=\"col\">{$straction}</th>"; echo "</tr>\n"; foreach ($order as $i => $qnum) { if ($qnum and empty($questions[$qnum])) { continue; } // If the questiontype is missing change the question type if ($qnum and !array_key_exists($questions[$qnum]->qtype, $QTYPES)) { $questions[$qnum]->qtype = 'missingtype'; } // Show the re-ordering field if the tool is turned on. // But don't show it in front of pagebreaks if they are hidden. if ($reordertool) { if ($qnum or $showbreaks) { echo '<tr><td><input type="text" name="o' . $i . '" size="2" value="' . (10 * $count + 10) . '" /></td>'; } else { echo '<tr><td><input type="hidden" name="o' . $i . '" size="2" value="' . (10 * $count + 10) . '" /></td>'; } } else { echo '<tr><td></td>'; } if ($qnum == 0) { // This is a page break if ($showbreaks) { echo '<td colspan ="3"> </td>'; echo '<td><table style="width:100%; line-height:11px; font-size:9px; margin: -5px -5px;"><tr>'; echo '<td><hr /></td>'; echo '<td style="width:50px;">Page break</td>'; echo '<td><hr /></td>'; echo '<td style="width:45px;">'; if ($count > 1) { echo "<a title=\"{$strmoveup}\" href=\"" . $pageurl->out_action(array('up' => $count)) . "\"><img\n src=\"{$CFG->pixpath}/t/up.gif\" class=\"iconsmall\" alt=\"{$strmoveup}\" /></a>"; } echo ' '; if ($count < $lastindex) { echo "<a title=\"{$strmovedown}\" href=\"" . $pageurl->out_action(array('down' => $count)) . "\"><img\n src=\"{$CFG->pixpath}/t/down.gif\" class=\"iconsmall\" alt=\"{$strmovedown}\" /></a>"; echo "<a title=\"{$strremove}\" href=\"" . $pageurl->out_action(array('delete' => $count)) . "\">\n <img src=\"{$CFG->pixpath}/t/delete.gif\" class=\"iconsmall\" alt=\"{$strremove}\" /></a>"; } echo '</td></tr></table></td>'; echo '<td colspan="2"> </td>'; } $count++; // missing </tr> here, if loop is broken, need to close the </tr> echo "</tr>"; continue; } $question = $questions[$qnum]; echo "<td>"; if ($count != 0) { echo "<a title=\"{$strmoveup}\" href=\"" . $pageurl->out_action(array('up' => $count)) . "\"><img\n src=\"{$CFG->pixpath}/t/up.gif\" class=\"iconsmall\" alt=\"{$strmoveup}\" /></a>"; } echo "</td>"; echo "<td>"; if ($count < $lastindex - 1) { echo "<a title=\"{$strmovedown}\" href=\"" . $pageurl->out_action(array('down' => $count)) . "\"><img\n src=\"{$CFG->pixpath}/t/down.gif\" class=\"iconsmall\" alt=\"{$strmovedown}\" /></a>"; } echo "</td>"; if (!$quiz->shufflequestions) { // Print and increment question number echo '<td>' . ($question->length ? $qno : ' ') . '</td>'; $qno += $question->length; } else { echo '<td> </td>'; } echo '<td>' . format_string($question->name) . '</td>'; echo "<td align=\"center\">"; print_question_icon($question); echo "</td>"; echo '<td align="left">'; if ($question->qtype == 'description') { echo "<input type=\"hidden\" name=\"q{$qnum}\" value=\"0\" /> \n"; } else { echo '<input type="text" name="q' . $qnum . '" size="2" value="' . $quiz->grades[$qnum] . '" tabindex="' . ($lastindex + $qno) . '" />'; } echo '</td><td align="center">'; if ($question->qtype != 'random') { echo quiz_question_preview_button($quiz, $question); } $returnurl = $pageurl->out(); $questionparams = array('returnurl' => $returnurl, 'cmid' => $quiz->cmid, 'id' => $question->id); $questionurl = new moodle_url("{$CFG->wwwroot}/question/question.php", $questionparams); if (question_has_capability_on($question, 'edit', $question->category) || question_has_capability_on($question, 'move', $question->category)) { echo "<a title=\"{$stredit}\" href=\"" . $questionurl->out() . "\">\n <img src=\"{$CFG->pixpath}/t/edit.gif\" class=\"iconsmall\" alt=\"{$stredit}\" /></a>"; } elseif (question_has_capability_on($question, 'view', $question->category)) { echo "<a title=\"{$strview}\" href=\"" . $questionurl->out(false, array('id' => $question->id)) . "\"><img\n src=\"{$CFG->pixpath}/i/info.gif\" alt=\"{$strview}\" /></a> "; } if ($allowdelete && question_has_capability_on($question, 'use', $question->category)) { // remove from quiz, not question delete. echo "<a title=\"{$strremove}\" href=\"" . $pageurl->out_action(array('delete' => $count)) . "\">\n <img src=\"{$CFG->pixpath}/t/removeright.gif\" class=\"iconsmall\" alt=\"{$strremove}\" /></a>"; } echo "</td></tr>"; $count++; $sumgrade += $quiz->grades[$qnum]; } echo "<tr><td colspan=\"6\" align=\"right\">\n"; print_string('total'); echo ": </td>"; echo "<td align=\"left\">\n"; echo "<strong>{$sumgrade}</strong>"; echo "</td><td> \n</td></tr>\n"; echo "<tr><td colspan=\"6\" align=\"right\">\n"; print_string('maximumgrade'); echo ": </td>"; echo "<td align=\"left\">\n"; echo '<input type="text" name="maxgrade" size="2" tabindex="' . ($qno + 1) . '" value="' . $quiz->grade . '" />'; echo '</td><td align="left">'; helpbutton("maxgrade", get_string("maximumgrade"), "quiz"); echo "</td></tr></table>\n"; echo '<div class="quizquestionlistcontrols"><input type="submit" value="' . get_string('savechanges') . '" />'; echo '<input type="hidden" name="savechanges" value="save" /></div>'; echo '</fieldset>'; echo "</form>\n"; /// Form to choose to show pagebreaks and to repaginate quiz echo '<form method="post" action="edit.php" id="showbreaks">'; echo '<fieldset class="invisiblefieldset">'; echo $pageurl->hidden_params_out(array('showbreaks', 'reordertool')); echo '<input type="hidden" name="sesskey" value="' . $USER->sesskey . '" />'; echo '<input type="hidden" name="showbreaks" value="0" />'; echo '<input type="checkbox" name="showbreaks" value="1"'; if ($showbreaks) { echo ' checked="checked"'; } echo ' onchange="getElementById(\'showbreaks\').submit(); return true;" />'; print_string('showbreaks', 'quiz'); if ($showbreaks) { $perpage = array(); for ($i = 0; $i <= 50; ++$i) { $perpage[$i] = $i; } $perpage[0] = get_string('allinone', 'quiz'); echo '<br /> '; print_string('repaginate', 'quiz', choose_from_menu($perpage, 'questionsperpage', $quiz->questionsperpage, '', '', '', true)); } echo '<br /><input type="hidden" name="reordertool" value="0" />'; echo '<input type="checkbox" name="reordertool" value="1"'; if ($reordertool) { echo ' checked="checked"'; } echo ' onchange="getElementById(\'showbreaks\').submit(); return true;" />'; print_string('reordertool', 'quiz'); echo ' '; helpbutton('reorderingtool', get_string('reordertool', 'quiz'), 'quiz'); echo '<div class="quizquestionlistcontrols"><input type="submit" name="repaginate" value="' . get_string('go') . '" /></div>'; echo '</fieldset>'; echo '</form>'; return $sumgrade; }