/** * Prints a list of quiz questions for the edit.php main view for edit * ($reordertool = false) and order and paging ($reordertool = true) tabs * * @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 moodle_url $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 * @param object $defaultcategoryobj * @param bool $canaddquestion is the user able to add and use questions anywere? * @param bool $canaddrandom is the user able to add random questions anywere? */ function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool, $quiz_qbanktool, $hasattempts, $defaultcategoryobj, $canaddquestion, $canaddrandom) { global $CFG, $DB, $OUTPUT; $strorder = get_string('order'); $strquestionname = get_string('questionname', 'quiz'); $strmaxmark = get_string('markedoutof', 'question'); $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. ?> <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 $strmaxmark; ?></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, $canaddquestion, $canaddrandom); } 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>'; } }
/** * Used by populate. Make up fake data for any missing questions. * @param \stdClass[] $slots the data about the slots and questions in the quiz. * @return \stdClass[] updated $slots array. */ protected function populate_missing_questions($slots) { // Address missing question types. foreach ($slots as $slot) { if ($slot->qtype === null) { // If the questiontype is missing change the question type. $slot->id = $slot->questionid; $slot->category = 0; $slot->qtype = 'missingtype'; $slot->name = get_string('missingquestion', 'quiz'); $slot->slot = $slot->slot; $slot->maxmark = 0; $slot->requireprevious = 0; $slot->questiontext = ' '; $slot->questiontextformat = FORMAT_HTML; $slot->length = 1; } else { if (!\question_bank::qtype_exists($slot->qtype)) { $slot->qtype = 'missingtype'; } } } return $slots; }