Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/mod/quiz/editlib.php
Go to the documentation of this file.
00001 <?php
00002 // This file is part of Moodle - http://moodle.org/
00003 //
00004 // Moodle is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU General Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // Moodle is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00016 
00017 
00032 defined('MOODLE_INTERNAL') || die();
00033 
00034 require_once($CFG->dirroot . '/mod/quiz/locallib.php');
00035 
00036 define('NUM_QS_TO_SHOW_IN_RANDOM', 3);
00037 
00043 function quiz_remove_question($quiz, $questionid) {
00044     global $DB;
00045 
00046     $questionids = explode(',', $quiz->questions);
00047     $key = array_search($questionid, $questionids);
00048     if ($key === false) {
00049         return;
00050     }
00051 
00052     unset($questionids[$key]);
00053     $quiz->questions = implode(',', $questionids);
00054     $DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id));
00055     $DB->delete_records('quiz_question_instances',
00056             array('quiz' => $quiz->instance, 'question' => $questionid));
00057 }
00058 
00065 function quiz_delete_empty_page($layout, $index) {
00066     $questionids = explode(',', $layout);
00067 
00068     if ($index < -1 || $index >= count($questionids) - 1) {
00069         return $layout;
00070     }
00071 
00072     if (($index >= 0 && $questionids[$index] != 0) || $questionids[$index + 1] != 0) {
00073         return $layout; // This was not an empty page.
00074     }
00075 
00076     unset($questionids[$index + 1]);
00077 
00078     return implode(',', $questionids);
00079 }
00080 
00094 function quiz_add_quiz_question($id, $quiz, $page = 0) {
00095     global $DB;
00096     $questions = explode(',', quiz_clean_layout($quiz->questions));
00097     if (in_array($id, $questions)) {
00098         return false;
00099     }
00100 
00101     // remove ending page break if it is not needed
00102     if ($breaks = array_keys($questions, 0)) {
00103         // determine location of the last two page breaks
00104         $end = end($breaks);
00105         $last = prev($breaks);
00106         $last = $last ? $last : -1;
00107         if (!$quiz->questionsperpage || (($end - $last - 1) < $quiz->questionsperpage)) {
00108             array_pop($questions);
00109         }
00110     }
00111     if (is_int($page) && $page >= 1) {
00112         $numofpages = quiz_number_of_pages($quiz->questions);
00113         if ($numofpages<$page) {
00114             //the page specified does not exist in quiz
00115             $page = 0;
00116         } else {
00117             // add ending page break - the following logic requires doing
00118             //this at this point
00119             $questions[] = 0;
00120             $currentpage = 1;
00121             $addnow = false;
00122             foreach ($questions as $question) {
00123                 if ($question == 0) {
00124                     $currentpage++;
00125                     //The current page is the one after the one we want to add on,
00126                     //so we add the question before adding the current page.
00127                     if ($currentpage == $page + 1) {
00128                         $questions_new[] = $id;
00129                     }
00130                 }
00131                 $questions_new[] = $question;
00132             }
00133             $questions = $questions_new;
00134         }
00135     }
00136     if ($page == 0) {
00137         // add question
00138         $questions[] = $id;
00139         // add ending page break
00140         $questions[] = 0;
00141     }
00142 
00143     // Save new questionslist in database
00144     $quiz->questions = implode(',', $questions);
00145     $DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id));
00146 
00147     // Add the new question instance.
00148     $instance = new stdClass();
00149     $instance->quiz = $quiz->id;
00150     $instance->question = $id;
00151     $instance->grade = $DB->get_field('question', 'defaultmark', array('id' => $id));
00152     $DB->insert_record('quiz_question_instances', $instance);
00153 }
00154 
00155 function quiz_add_random_questions($quiz, $addonpage, $categoryid, $number,
00156         $includesubcategories) {
00157     global $DB;
00158 
00159     $category = $DB->get_record('question_categories', array('id' => $categoryid));
00160     if (!$category) {
00161         print_error('invalidcategoryid', 'error');
00162     }
00163 
00164     $catcontext = get_context_instance_by_id($category->contextid);
00165     require_capability('moodle/question:useall', $catcontext);
00166 
00167     // Find existing random questions in this category that are
00168     // not used by any quiz.
00169     if ($existingquestions = $DB->get_records_sql(
00170             "SELECT q.id, q.qtype FROM {question} q
00171             WHERE qtype = 'random'
00172                 AND category = ?
00173                 AND " . $DB->sql_compare_text('questiontext') . " = ?
00174                 AND NOT EXISTS (
00175                         SELECT *
00176                           FROM {quiz_question_instances}
00177                          WHERE question = q.id)
00178             ORDER BY id", array($category->id, $includesubcategories))) {
00179         // Take as many of these as needed.
00180         while (($existingquestion = array_shift($existingquestions)) && $number > 0) {
00181             quiz_add_quiz_question($existingquestion->id, $quiz, $addonpage);
00182             $number -= 1;
00183         }
00184     }
00185 
00186     if ($number <= 0) {
00187         return;
00188     }
00189 
00190     // More random questions are needed, create them.
00191     for ($i = 0; $i < $number; $i += 1) {
00192         $form = new stdClass();
00193         $form->questiontext = array('text' => $includesubcategories, 'format' => 0);
00194         $form->category = $category->id . ',' . $category->contextid;
00195         $form->defaultmark = 1;
00196         $form->hidden = 1;
00197         $form->stamp = make_unique_id_code(); // Set the unique code (not to be changed)
00198         $question = new stdClass();
00199         $question->qtype = 'random';
00200         $question = question_bank::get_qtype('random')->save_question($question, $form);
00201         if (!isset($question->id)) {
00202             print_error('cannotinsertrandomquestion', 'quiz');
00203         }
00204         quiz_add_quiz_question($question->id, $quiz, $addonpage);
00205     }
00206 }
00207 
00214 function quiz_add_page_break_at($layout, $index) {
00215     $questionids = explode(',', $layout);
00216     if ($index < 0 || $index >= count($questionids)) {
00217         return $layout;
00218     }
00219 
00220     array_splice($questionids, $index, 0, '0');
00221 
00222     return implode(',', $questionids);
00223 }
00224 
00231 function quiz_add_page_break_after($layout, $questionid) {
00232     $questionids = explode(',', $layout);
00233     $key = array_search($questionid, $questionids);
00234     if ($key === false || !$questionid) {
00235         return $layout;
00236     }
00237 
00238     array_splice($questionids, $key + 1, 0, '0');
00239 
00240     return implode(',', $questionids);
00241 }
00242 
00248 function quiz_save_new_layout($quiz) {
00249     global $DB;
00250     $DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id));
00251     quiz_delete_previews($quiz);
00252     quiz_update_sumgrades($quiz);
00253 }
00254 
00265 function quiz_update_question_instance($grade, $questionid, $quiz) {
00266     global $DB;
00267     $instance = $DB->get_record('quiz_question_instances', array('quiz' => $quiz->id,
00268             'question' => $questionid));
00269     $slot = quiz_get_slot_for_question($quiz, $questionid);
00270 
00271     if (!$instance || !$slot) {
00272         throw new coding_exception('Attempt to change the grade of a quesion not in the quiz.');
00273     }
00274 
00275     if (abs($grade - $instance->grade) < 1e-7) {
00276         // Grade has not changed. Nothing to do.
00277         return;
00278     }
00279 
00280     $instance->grade = $grade;
00281     $DB->update_record('quiz_question_instances', $instance);
00282     question_engine::set_max_mark_in_attempts(new qubaids_for_quiz($quiz->id),
00283             $slot, $grade);
00284 }
00285 
00286 // Private function used by the following two.
00287 function _quiz_move_question($layout, $questionid, $shift) {
00288     if (!$questionid || !($shift == 1 || $shift == -1)) {
00289         return $layout;
00290     }
00291 
00292     $questionids = explode(',', $layout);
00293     $key = array_search($questionid, $questionids);
00294     if ($key === false) {
00295         return $layout;
00296     }
00297 
00298     $otherkey = $key + $shift;
00299     if ($otherkey < 0 || $otherkey >= count($questionids) - 1) {
00300         return $layout;
00301     }
00302 
00303     $temp = $questionids[$otherkey];
00304     $questionids[$otherkey] = $questionids[$key];
00305     $questionids[$key] = $temp;
00306 
00307     return implode(',', $questionids);
00308 }
00309 
00317 function quiz_move_question_up($layout, $questionid) {
00318     return _quiz_move_question($layout, $questionid, -1);
00319 }
00320 
00328 function quiz_move_question_down($layout, $questionid) {
00329     return _quiz_move_question($layout, $questionid, +1);
00330 }
00331 
00347 function quiz_print_question_list($quiz, $pageurl, $allowdelete, $reordertool,
00348         $quiz_qbanktool, $hasattempts, $defaultcategoryobj) {
00349     global $CFG, $DB, $OUTPUT;
00350     $strorder = get_string('order');
00351     $strquestionname = get_string('questionname', 'quiz');
00352     $strgrade = get_string('grade');
00353     $strremove = get_string('remove', 'quiz');
00354     $stredit = get_string('edit');
00355     $strview = get_string('view');
00356     $straction = get_string('action');
00357     $strmove = get_string('move');
00358     $strmoveup = get_string('moveup');
00359     $strmovedown = get_string('movedown');
00360     $strsave = get_string('save', 'quiz');
00361     $strreorderquestions = get_string('reorderquestions', 'quiz');
00362 
00363     $strselectall = get_string('selectall', 'quiz');
00364     $strselectnone = get_string('selectnone', 'quiz');
00365     $strtype = get_string('type', 'quiz');
00366     $strpreview = get_string('preview', 'quiz');
00367 
00368     if ($quiz->questions) {
00369         list($usql, $params) = $DB->get_in_or_equal(explode(',', $quiz->questions));
00370         $params[] = $quiz->id;
00371         $questions = $DB->get_records_sql("SELECT q.*, qc.contextid, qqi.grade as maxmark
00372                               FROM {question} q
00373                               JOIN {question_categories} qc ON qc.id = q.category
00374                               JOIN {quiz_question_instances} qqi ON qqi.question = q.id
00375                              WHERE q.id $usql AND qqi.quiz = ?", $params);
00376     } else {
00377         $questions = array();
00378     }
00379 
00380     $layout = quiz_clean_layout($quiz->questions);
00381     $order = explode(',', $layout);
00382     $lastindex = count($order) - 1;
00383 
00384     $disabled = '';
00385     $pagingdisabled = '';
00386     if ($hasattempts) {
00387         $disabled = 'disabled="disabled"';
00388     }
00389     if ($hasattempts || $quiz->shufflequestions) {
00390         $pagingdisabled = 'disabled="disabled"';
00391     }
00392 
00393     $reordercontrolssetdefaultsubmit = '<div style="display:none;">' .
00394         '<input type="submit" name="savechanges" value="' .
00395         $strreorderquestions . '" ' . $pagingdisabled . ' /></div>';
00396     $reordercontrols1 = '<div class="addnewpagesafterselected">' .
00397         '<input type="submit" name="addnewpagesafterselected" value="' .
00398         get_string('addnewpagesafterselected', 'quiz') . '"  ' .
00399         $pagingdisabled . ' /></div>';
00400     $reordercontrols1 .= '<div class="quizdeleteselected">' .
00401         '<input type="submit" name="quizdeleteselected" ' .
00402         'onclick="return confirm(\'' .
00403         get_string('areyousureremoveselected', 'quiz') . '\');" value="' .
00404         get_string('removeselected', 'quiz') . '"  ' . $disabled . ' /></div>';
00405 
00406     $a = '<input name="moveselectedonpagetop" type="text" size="2" ' .
00407         $pagingdisabled . ' />';
00408     $b = '<input name="moveselectedonpagebottom" type="text" size="2" ' .
00409         $pagingdisabled . ' />';
00410 
00411     $reordercontrols2top = '<div class="moveselectedonpage">' .
00412         get_string('moveselectedonpage', 'quiz', $a) .
00413         '<input type="submit" name="savechanges" value="' .
00414         $strmove . '"  ' . $pagingdisabled . ' />' . '
00415         <br /><input type="submit" name="savechanges" value="' .
00416         $strreorderquestions . '" /></div>';
00417     $reordercontrols2bottom = '<div class="moveselectedonpage">' .
00418         '<input type="submit" name="savechanges" value="' .
00419         $strreorderquestions . '" /><br />' .
00420         get_string('moveselectedonpage', 'quiz', $b) .
00421         '<input type="submit" name="savechanges" value="' .
00422         $strmove . '"  ' . $pagingdisabled . ' /> ' . '</div>';
00423 
00424     $reordercontrols3 = '<a href="javascript:select_all_in(\'FORM\', null, ' .
00425             '\'quizquestions\');">' .
00426             $strselectall . '</a> /';
00427     $reordercontrols3.=    ' <a href="javascript:deselect_all_in(\'FORM\', ' .
00428             'null, \'quizquestions\');">' .
00429             $strselectnone . '</a>';
00430 
00431     $reordercontrolstop = '<div class="reordercontrols">' .
00432             $reordercontrolssetdefaultsubmit .
00433             $reordercontrols1 . $reordercontrols2top . $reordercontrols3 . "</div>";
00434     $reordercontrolsbottom = '<div class="reordercontrols">' .
00435             $reordercontrolssetdefaultsubmit .
00436             $reordercontrols2bottom . $reordercontrols1 . $reordercontrols3 . "</div>";
00437 
00438     if ($reordertool) {
00439         echo '<form method="post" action="edit.php" id="quizquestions"><div>';
00440 
00441         echo html_writer::input_hidden_params($pageurl);
00442         echo '<input type="hidden" name="sesskey" value="' . sesskey() . '" />';
00443 
00444         echo $reordercontrolstop;
00445     }
00446 
00447     //the current question ordinal (no descriptions)
00448     $qno = 1;
00449     //the current question (includes questions and descriptions)
00450     $questioncount = 0;
00451     //the current page number in iteration
00452     $pagecount = 0;
00453 
00454     $pageopen = false;
00455 
00456     $returnurl = str_replace($CFG->wwwroot, '', $pageurl->out(false));
00457     $questiontotalcount = count($order);
00458 
00459     foreach ($order as $count => $qnum) {
00460 
00461         $reordercheckbox = '';
00462         $reordercheckboxlabel = '';
00463         $reordercheckboxlabelclose = '';
00464 
00465         // If the questiontype is missing change the question type
00466         if ($qnum && !array_key_exists($qnum, $questions)) {
00467             $fakequestion = new stdClass();
00468             $fakequestion->id = $qnum;
00469             $fakequestion->category = 0;
00470             $fakequestion->qtype = 'missingtype';
00471             $fakequestion->name = get_string('missingquestion', 'quiz');
00472             $fakequestion->questiontext = ' ';
00473             $fakequestion->questiontextformat = FORMAT_HTML;
00474             $fakequestion->length = 1;
00475             $questions[$qnum] = $fakequestion;
00476             $quiz->grades[$qnum] = 0;
00477 
00478         } else if ($qnum && !question_bank::qtype_exists($questions[$qnum]->qtype)) {
00479             $questions[$qnum]->qtype = 'missingtype';
00480         }
00481 
00482         if ($qnum != 0 || ($qnum == 0 && !$pageopen)) {
00483             //this is either a question or a page break after another
00484             //        (no page is currently open)
00485             if (!$pageopen) {
00486                 //if no page is open, start display of a page
00487                 $pagecount++;
00488                 echo  '<div class="quizpage"><span class="pagetitle">' .
00489                         get_string('page') . '&nbsp;' . $pagecount .
00490                         '</span><div class="pagecontent">';
00491                 $pageopen = true;
00492             }
00493             if ($qnum == 0  && $count < $questiontotalcount) {
00494                 // This is the second successive page break. Tell the user the page is empty.
00495                 echo '<div class="pagestatus">';
00496                 print_string('noquestionsonpage', 'quiz');
00497                 echo '</div>';
00498                 if ($allowdelete) {
00499                     echo '<div class="quizpagedelete">';
00500                     echo $OUTPUT->action_icon($pageurl->out(true,
00501                             array('deleteemptypage' => $count - 1, 'sesskey'=>sesskey())),
00502                             new pix_icon('t/delete', $strremove),
00503                             new component_action('click',
00504                                     'M.core_scroll_manager.save_scroll_action'),
00505                             array('title' => $strremove));
00506                     echo '</div>';
00507                 }
00508             }
00509 
00510             if ($qnum != 0) {
00511                 $question = $questions[$qnum];
00512                 $questionparams = array(
00513                         'returnurl' => $returnurl,
00514                         'cmid' => $quiz->cmid,
00515                         'id' => $question->id);
00516                 $questionurl = new moodle_url('/question/question.php',
00517                         $questionparams);
00518                 $questioncount++;
00519                 //this is an actual question
00520 
00521                 /* Display question start */
00522                 ?>
00523 <div class="question">
00524     <div class="questioncontainer <?php echo $question->qtype; ?>">
00525         <div class="qnum">
00526                 <?php
00527                 $reordercheckbox = '';
00528                 $reordercheckboxlabel = '';
00529                 $reordercheckboxlabelclose = '';
00530                 if ($reordertool) {
00531                     $reordercheckbox = '<input type="checkbox" name="s' . $question->id .
00532                         '" id="s' . $question->id . '" />';
00533                     $reordercheckboxlabel = '<label for="s' . $question->id . '">';
00534                     $reordercheckboxlabelclose = '</label>';
00535                 }
00536                 if ($question->length == 0) {
00537                     $qnodisplay = get_string('infoshort', 'quiz');
00538                 } else if ($quiz->shufflequestions) {
00539                     $qnodisplay = '?';
00540                 } else {
00541                     if ($qno > 999 || ($reordertool && $qno > 99)) {
00542                         $qnodisplay = html_writer::tag('small', $qno);
00543                     } else {
00544                         $qnodisplay = $qno;
00545                     }
00546                     $qno += $question->length;
00547                 }
00548                 echo $reordercheckboxlabel . $qnodisplay . $reordercheckboxlabelclose .
00549                         $reordercheckbox;
00550 
00551                 ?>
00552         </div>
00553         <div class="content">
00554             <div class="questioncontrols">
00555                 <?php
00556                 if ($count != 0) {
00557                     if (!$hasattempts) {
00558                         $upbuttonclass = '';
00559                         if ($count >= $lastindex - 1) {
00560                             $upbuttonclass = 'upwithoutdown';
00561                         }
00562                         echo $OUTPUT->action_icon($pageurl->out(true,
00563                                 array('up' => $question->id, 'sesskey'=>sesskey())),
00564                                 new pix_icon('t/up', $strmoveup),
00565                                 new component_action('click',
00566                                         'M.core_scroll_manager.save_scroll_action'),
00567                                 array('title' => $strmoveup));
00568                     }
00569 
00570                 }
00571                 if ($count < $lastindex - 1) {
00572                     if (!$hasattempts) {
00573                         echo $OUTPUT->action_icon($pageurl->out(true,
00574                                 array('down' => $question->id, 'sesskey'=>sesskey())),
00575                                 new pix_icon('t/down', $strmovedown),
00576                                 new component_action('click',
00577                                         'M.core_scroll_manager.save_scroll_action'),
00578                                 array('title' => $strmovedown));
00579                     }
00580                 }
00581                 if ($allowdelete && ($question->qtype == 'missingtype' ||
00582                         question_has_capability_on($question, 'use', $question->category))) {
00583                     // remove from quiz, not question delete.
00584                     if (!$hasattempts) {
00585                         echo $OUTPUT->action_icon($pageurl->out(true,
00586                                 array('remove' => $question->id, 'sesskey'=>sesskey())),
00587                                 new pix_icon('t/delete', $strremove),
00588                                 new component_action('click',
00589                                         'M.core_scroll_manager.save_scroll_action'),
00590                                 array('title' => $strremove));
00591                     }
00592                 }
00593                 ?>
00594             </div><?php
00595                 if (!in_array($question->qtype, array('description', 'missingtype')) && !$reordertool) {
00596                     ?>
00597 <div class="points">
00598 <form method="post" action="edit.php" class="quizsavegradesform"><div>
00599     <fieldset class="invisiblefieldset" style="display: block;">
00600     <label for="<?php echo "inputq$question->id" ?>"><?php echo $strgrade; ?></label>:<br />
00601     <input type="hidden" name="sesskey" value="<?php echo sesskey() ?>" />
00602     <?php echo html_writer::input_hidden_params($pageurl); ?>
00603     <input type="hidden" name="savechanges" value="save" />
00604                     <?php
00605                     echo '<input type="text" name="g' . $question->id .
00606                             '" id="inputq' . $question->id .
00607                             '" size="' . ($quiz->decimalpoints + 2) .
00608                             '" value="' . (0 + $quiz->grades[$qnum]) .
00609                             '" tabindex="' . ($lastindex + $qno) . '" />';
00610                     ?>
00611         <input type="submit" class="pointssubmitbutton" value="<?php echo $strsave; ?>" />
00612     </fieldset>
00613                     <?php
00614                     if ($question->qtype == 'random') {
00615                         echo '<a href="' . $questionurl->out() .
00616                                 '" class="configurerandomquestion">' .
00617                                 get_string("configurerandomquestion", "quiz") . '</a>';
00618                     }
00619 
00620                     ?>
00621 </div>
00622 </form>
00623 
00624             </div>
00625                     <?php
00626                 } else if ($reordertool) {
00627                     if ($qnum) {
00628                         ?>
00629 <div class="qorder">
00630                         <?php
00631                         echo '<input type="text" name="o' . $question->id .
00632                                 '" size="2" value="' . (10*$count + 10) .
00633                                 '" tabindex="' . ($lastindex + $qno) . '" />';
00634                         ?>
00635 </div>
00636                         <?php
00637                     }
00638                 }
00639                 ?>
00640             <div class="questioncontentcontainer">
00641                 <?php
00642                 if ($question->qtype == 'random') { // it is a random question
00643                     if (!$reordertool) {
00644                         quiz_print_randomquestion($question, $pageurl, $quiz, $quiz_qbanktool);
00645                     } else {
00646                         quiz_print_randomquestion_reordertool($question, $pageurl, $quiz);
00647                     }
00648                 } else { // it is a single question
00649                     if (!$reordertool) {
00650                         quiz_print_singlequestion($question, $returnurl, $quiz);
00651                     } else {
00652                         quiz_print_singlequestion_reordertool($question, $returnurl, $quiz);
00653                     }
00654                 }
00655                 ?>
00656             </div>
00657         </div>
00658     </div>
00659 </div>
00660 
00661                 <?php
00662             }
00663         }
00664         //a page break: end the existing page.
00665         if ($qnum == 0) {
00666             if ($pageopen) {
00667                 if (!$reordertool && !($quiz->shufflequestions &&
00668                         $count < $questiontotalcount - 1)) {
00669                     quiz_print_pagecontrols($quiz, $pageurl, $pagecount,
00670                             $hasattempts, $defaultcategoryobj);
00671                 } else if ($count < $questiontotalcount - 1) {
00672                     //do not include the last page break for reordering
00673                     //to avoid creating a new extra page in the end
00674                     echo '<input type="hidden" name="opg' . $pagecount . '" size="2" value="' .
00675                             (10*$count + 10) . '" />';
00676                 }
00677                 echo "</div></div>";
00678 
00679                 if (!$reordertool && !$quiz->shufflequestions) {
00680                     echo $OUTPUT->container_start('addpage');
00681                     $url = new moodle_url($pageurl->out_omit_querystring(),
00682                             array('cmid' => $quiz->cmid, 'courseid' => $quiz->course,
00683                                     'addpage' => $count, 'sesskey' => sesskey()));
00684                     echo $OUTPUT->single_button($url, get_string('addpagehere', 'quiz'), 'post',
00685                             array('disabled' => $hasattempts,
00686                             'actions' => array(new component_action('click',
00687                                     'M.core_scroll_manager.save_scroll_action'))));
00688                     echo $OUTPUT->container_end();
00689                 }
00690                 $pageopen = false;
00691                 $count++;
00692             }
00693         }
00694 
00695     }
00696     if ($reordertool) {
00697         echo $reordercontrolsbottom;
00698         echo '</div></form>';
00699     }
00700 }
00701 
00711 function quiz_print_pagecontrols($quiz, $pageurl, $page, $hasattempts, $defaultcategoryobj) {
00712     global $CFG, $OUTPUT;
00713     static $randombuttoncount = 0;
00714     $randombuttoncount++;
00715     echo '<div class="pagecontrols">';
00716 
00717     // Get the current context
00718     $thiscontext = get_context_instance(CONTEXT_COURSE, $quiz->course);
00719     $contexts = new question_edit_contexts($thiscontext);
00720 
00721     // Get the default category.
00722     list($defaultcategoryid) = explode(',', $pageurl->param('cat'));
00723     if (empty($defaultcategoryid)) {
00724         $defaultcategoryid = $defaultcategoryobj->id;
00725     }
00726 
00727     // Create the url the question page will return to
00728     $returnurladdtoquiz = new moodle_url($pageurl, array('addonpage' => $page));
00729 
00730     // Print a button linking to the choose question type page.
00731     $returnurladdtoquiz = str_replace($CFG->wwwroot, '', $returnurladdtoquiz->out(false));
00732     $newquestionparams = array('returnurl' => $returnurladdtoquiz,
00733             'cmid' => $quiz->cmid, 'appendqnumstring' => 'addquestion');
00734     create_new_question_button($defaultcategoryid, $newquestionparams,
00735             get_string('addaquestion', 'quiz'),
00736             get_string('createquestionandadd', 'quiz'), $hasattempts);
00737 
00738     if ($hasattempts) {
00739         $disabled = 'disabled="disabled"';
00740     } else {
00741         $disabled = '';
00742     }
00743     ?>
00744     <div class="singlebutton">
00745         <form class="randomquestionform" action="<?php echo $CFG->wwwroot;
00746                 ?>/mod/quiz/addrandom.php" method="get">
00747             <div>
00748                 <input type="hidden" class="addonpage_formelement" name="addonpage" value="<?php
00749                         echo $page; ?>" />
00750                 <input type="hidden" name="cmid" value="<?php echo $quiz->cmid; ?>" />
00751                 <input type="hidden" name="courseid" value="<?php echo $quiz->course; ?>" />
00752                 <input type="hidden" name="category" value="<?php
00753                         echo $pageurl->param('cat'); ?>" />
00754                 <input type="hidden" name="returnurl" value="<?php
00755                         echo s(str_replace($CFG->wwwroot, '', $pageurl->out(false))); ?>" />
00756                 <input type="submit" id="addrandomdialoglaunch_<?php
00757                         echo $randombuttoncount; ?>" value="<?php
00758                         echo get_string('addarandomquestion', 'quiz'); ?>" <?php
00759                         echo " $disabled"; ?> />
00760             </div>
00761         </form>
00762     </div>
00763     <?php echo $OUTPUT->help_icon('addarandomquestion', 'quiz'); ?>
00764     <?php
00765     echo "\n</div>";
00766 }
00767 
00776 function quiz_print_singlequestion($question, $returnurl, $quiz) {
00777     echo '<div class="singlequestion ' . $question->qtype . '">';
00778     echo quiz_question_edit_button($quiz->cmid, $question, $returnurl,
00779             quiz_question_tostring($question) . ' ');
00780     echo '<span class="questiontype">';
00781     echo print_question_icon($question);
00782     echo ' ' . question_bank::get_qtype_name($question->qtype) . '</span>';
00783     echo '<span class="questionpreview">' .
00784             quiz_question_preview_button($quiz, $question, true) . '</span>';
00785     echo "</div>\n";
00786 }
00796 function quiz_print_randomquestion(&$question, &$pageurl, &$quiz, $quiz_qbanktool) {
00797     global $DB, $OUTPUT;
00798     echo '<div class="quiz_randomquestion">';
00799 
00800     if (!$category = $DB->get_record('question_categories',
00801             array('id' => $question->category))) {
00802         echo $OUTPUT->notification('Random question category not found!');
00803         return;
00804     }
00805 
00806     echo '<div class="randomquestionfromcategory">';
00807     echo print_question_icon($question);
00808     print_random_option_icon($question);
00809     echo ' ' . get_string('randomfromcategory', 'quiz') . '</div>';
00810 
00811     $a = new stdClass();
00812     $a->arrow = $OUTPUT->rarrow();
00813     $strshowcategorycontents = get_string('showcategorycontents', 'quiz', $a);
00814 
00815     $openqbankurl = $pageurl->out(true, array('qbanktool' => 1,
00816             'cat' => $category->id . ',' . $category->contextid));
00817     $linkcategorycontents = ' <a href="' . $openqbankurl . '">' . $strshowcategorycontents . '</a>';
00818 
00819     echo '<div class="randomquestioncategory">';
00820     echo '<a href="' . $openqbankurl . '" title="' . $strshowcategorycontents . '">' .
00821             $category->name . '</a>';
00822     echo '<span class="questionpreview">' .
00823             quiz_question_preview_button($quiz, $question, true) . '</span>';
00824     echo '</div>';
00825 
00826     $questionids = question_bank::get_qtype('random')->get_available_questions_from_category(
00827             $category->id, $question->questiontext == '1', '0');
00828     $questioncount = count($questionids);
00829 
00830     echo '<div class="randomquestionqlist">';
00831     if ($questioncount == 0) {
00832         // No questions in category, give an error plus instructions
00833         echo '<span class="error">';
00834         print_string('noquestionsnotinuse', 'quiz');
00835         echo '</span>';
00836         echo '<br />';
00837 
00838         // Embed the link into the string with instructions
00839         $a = new stdClass();
00840         $a->catname = '<strong>' . $category->name . '</strong>';
00841         $a->link = $linkcategorycontents;
00842         echo get_string('addnewquestionsqbank', 'quiz', $a);
00843 
00844     } else {
00845         // Category has questions
00846 
00847         // Get a sample from the database,
00848         $questionidstoshow = array_slice($questionids, 0, NUM_QS_TO_SHOW_IN_RANDOM);
00849         $questionstoshow = $DB->get_records_list('question', 'id', $questionidstoshow,
00850                 '', 'id, qtype, name, questiontext, questiontextformat');
00851 
00852         // list them,
00853         echo '<ul>';
00854         foreach ($questionstoshow as $question) {
00855             echo '<li>' . quiz_question_tostring($question, true) . '</li>';
00856         }
00857 
00858         // and then display the total number.
00859         echo '<li class="totalquestionsinrandomqcategory">';
00860         if ($questioncount > NUM_QS_TO_SHOW_IN_RANDOM) {
00861             echo '... ';
00862         }
00863         print_string('totalquestionsinrandomqcategory', 'quiz', $questioncount);
00864         echo ' ' . $linkcategorycontents;
00865         echo '</li>';
00866         echo '</ul>';
00867     }
00868 
00869     echo '</div>';
00870     echo '<div class="randomquestioncategorycount">';
00871     echo '</div>';
00872     echo '</div>';
00873 }
00874 
00883 function quiz_print_singlequestion_reordertool($question, $returnurl, $quiz) {
00884     echo '<div class="singlequestion ' . $question->qtype . '">';
00885     echo '<label for="s' . $question->id . '">';
00886     echo print_question_icon($question);
00887     echo ' ' . quiz_question_tostring($question);
00888     echo '</label>';
00889     echo '<span class="questionpreview">' .
00890             quiz_question_action_icons($quiz, $quiz->cmid, $question, $returnurl) . '</span>';
00891     echo "</div>\n";
00892 }
00893 
00902 function quiz_print_randomquestion_reordertool(&$question, &$pageurl, &$quiz) {
00903     global $DB, $OUTPUT;
00904 
00905     // Load the category, and the number of available questions in it.
00906     if (!$category = $DB->get_record('question_categories', array('id' => $question->category))) {
00907         echo $OUTPUT->notification('Random question category not found!');
00908         return;
00909     }
00910     $questioncount = count(question_bank::get_qtype(
00911             'random')->get_available_questions_from_category(
00912             $category->id, $question->questiontext == '1', '0'));
00913 
00914     $reordercheckboxlabel = '<label for="s' . $question->id . '">';
00915     $reordercheckboxlabelclose = '</label>';
00916 
00917     echo '<div class="quiz_randomquestion">';
00918     echo '<div class="randomquestionfromcategory">';
00919     echo $reordercheckboxlabel;
00920     echo print_question_icon($question);
00921     print_random_option_icon($question);
00922 
00923     if ($questioncount == 0) {
00924         echo '<span class="error">';
00925         print_string('empty', 'quiz');
00926         echo '</span> ';
00927     }
00928 
00929     print_string('random', 'quiz');
00930     echo ": $reordercheckboxlabelclose</div>";
00931 
00932     echo '<div class="randomquestioncategory">';
00933     echo $reordercheckboxlabel . $category->name . $reordercheckboxlabelclose;
00934     echo '<span class="questionpreview">';
00935     echo quiz_question_preview_button($quiz, $question, false);
00936     echo '</span>';
00937     echo "</div>";
00938 
00939     echo '<div class="randomquestioncategorycount">';
00940     echo '</div>';
00941     echo '</div>';
00942 }
00943 
00948 function print_random_option_icon($question) {
00949     global $OUTPUT;
00950     if (!empty($question->questiontext)) {
00951         $icon = 'withsubcat';
00952         $tooltip = get_string('randomwithsubcat', 'quiz');
00953     } else {
00954         $icon = 'nosubcat';
00955         $tooltip = get_string('randomnosubcat', 'quiz');
00956     }
00957     echo '<img src="' . $OUTPUT->pix_url('i/' . $icon) . '" alt="' .
00958             $tooltip . '" title="' . $tooltip . '" class="uihint" />';
00959 }
00960 
00970 function quiz_question_tostring($question, $showicon = false,
00971         $showquestiontext = true, $return = true) {
00972     global $COURSE;
00973     $result = '';
00974     $result .= '<span class="questionname">';
00975     if ($showicon) {
00976         $result .= print_question_icon($question, true);
00977         echo ' ';
00978     }
00979     $result .= shorten_text(format_string($question->name), 200) . '</span>';
00980     if ($showquestiontext) {
00981         $formatoptions = new stdClass();
00982         $formatoptions->noclean = true;
00983         $formatoptions->para = false;
00984         $questiontext = strip_tags(format_text($question->questiontext,
00985                 $question->questiontextformat,
00986                 $formatoptions, $COURSE->id));
00987         $questiontext = shorten_text($questiontext, 200);
00988         $result .= '<span class="questiontext">';
00989         if (!empty($questiontext)) {
00990             $result .= $questiontext;
00991         } else {
00992             $result .= '<span class="error">';
00993             $result .= get_string('questiontextisempty', 'quiz');
00994             $result .= '</span>';
00995         }
00996         $result .= '</span>';
00997     }
00998     if ($return) {
00999         return $result;
01000     } else {
01001         echo $result;
01002     }
01003 }
01004 
01011 class question_bank_add_to_quiz_action_column extends question_bank_action_column_base {
01012     protected $stradd;
01013 
01014     public function init() {
01015         parent::init();
01016         $this->stradd = get_string('addtoquiz', 'quiz');
01017     }
01018 
01019     public function get_name() {
01020         return 'addtoquizaction';
01021     }
01022 
01023     protected function display_content($question, $rowclasses) {
01024         // for RTL languages: switch right and left arrows
01025         if (right_to_left()) {
01026             $movearrow = 't/removeright';
01027         } else {
01028             $movearrow = 't/moveleft';
01029         }
01030         $this->print_icon($movearrow, $this->stradd, $this->qbank->add_to_quiz_url($question->id));
01031     }
01032 
01033     public function get_required_fields() {
01034         return array('q.id');
01035     }
01036 }
01037 
01044 class question_bank_question_name_text_column extends question_bank_question_name_column {
01045     public function get_name() {
01046         return 'questionnametext';
01047     }
01048 
01049     protected function display_content($question, $rowclasses) {
01050         echo '<div>';
01051         $labelfor = $this->label_for($question);
01052         if ($labelfor) {
01053             echo '<label for="' . $labelfor . '">';
01054         }
01055         echo quiz_question_tostring($question, false, true, true);
01056         if ($labelfor) {
01057             echo '</label>';
01058         }
01059         echo '</div>';
01060     }
01061 
01062     public function get_required_fields() {
01063         $fields = parent::get_required_fields();
01064         $fields[] = 'q.questiontext';
01065         $fields[] = 'q.questiontextformat';
01066         return $fields;
01067     }
01068 }
01069 
01076 class quiz_question_bank_view extends question_bank_view {
01077     protected $quizhasattempts = false;
01079     protected $quiz = false;
01080 
01089     public function __construct($contexts, $pageurl, $course, $cm, $quiz) {
01090         parent::__construct($contexts, $pageurl, $course, $cm);
01091         $this->quiz = $quiz;
01092     }
01093 
01094     protected function known_field_types() {
01095         $types = parent::known_field_types();
01096         $types[] = new question_bank_add_to_quiz_action_column($this);
01097         $types[] = new question_bank_question_name_text_column($this);
01098         return $types;
01099     }
01100 
01101     protected function wanted_columns() {
01102         return array('addtoquizaction', 'checkbox', 'qtype', 'questionnametext',
01103                 'editaction', 'previewaction');
01104     }
01105 
01106     protected function default_sort() {
01107         return array('qtype' => 1, 'questionnametext' => 1);
01108     }
01109 
01116     public function set_quiz_has_attempts($quizhasattempts) {
01117         $this->quizhasattempts = $quizhasattempts;
01118         if ($quizhasattempts && isset($this->visiblecolumns['addtoquizaction'])) {
01119             unset($this->visiblecolumns['addtoquizaction']);
01120         }
01121     }
01122 
01123     public function preview_question_url($question) {
01124         return quiz_question_preview_url($this->quiz, $question);
01125     }
01126 
01127     public function add_to_quiz_url($questionid) {
01128         global $CFG;
01129         $params = $this->baseurl->params();
01130         $params['addquestion'] = $questionid;
01131         $params['sesskey'] = sesskey();
01132         return new moodle_url('/mod/quiz/edit.php', $params);
01133     }
01134 
01135     public function display($tabname, $page, $perpage, $cat,
01136             $recurse, $showhidden, $showquestiontext) {
01137         global $OUTPUT;
01138         if ($this->process_actions_needing_ui()) {
01139             return;
01140         }
01141 
01142         // Display the current category.
01143         if (!$category = $this->get_current_category($cat)) {
01144             return;
01145         }
01146         $this->print_category_info($category);
01147 
01148         echo $OUTPUT->box_start('generalbox questionbank');
01149 
01150         $this->display_category_form($this->contexts->having_one_edit_tab_cap($tabname),
01151                 $this->baseurl, $cat);
01152 
01153         // continues with list of questions
01154         $this->display_question_list($this->contexts->having_one_edit_tab_cap($tabname),
01155                 $this->baseurl, $cat, $this->cm, $recurse, $page,
01156                 $perpage, $showhidden, $showquestiontext,
01157                 $this->contexts->having_cap('moodle/question:add'));
01158 
01159         $this->display_options($recurse, $showhidden, $showquestiontext);
01160         echo $OUTPUT->box_end();
01161     }
01162 
01163     protected function print_choose_category_message($categoryandcontext) {
01164         global $OUTPUT;
01165         echo $OUTPUT->box_start('generalbox questionbank');
01166         $this->display_category_form($this->contexts->having_one_edit_tab_cap('edit'),
01167                 $this->baseurl, $categoryandcontext);
01168         echo "<p style=\"text-align:center;\"><b>";
01169         print_string('selectcategoryabove', 'question');
01170         echo "</b></p>";
01171         echo $OUTPUT->box_end();
01172     }
01173 
01174     protected function print_category_info($category) {
01175         $formatoptions = new stdClass();
01176         $formatoptions->noclean = true;
01177         $strcategory = get_string('category', 'quiz');
01178         echo '<div class="categoryinfo"><div class="categorynamefieldcontainer">' .
01179                 $strcategory;
01180         echo ': <span class="categorynamefield">';
01181         echo shorten_text(strip_tags(format_string($category->name)), 60);
01182         echo '</span></div><div class="categoryinfofieldcontainer">' .
01183                 '<span class="categoryinfofield">';
01184         echo shorten_text(strip_tags(format_text($category->info, $category->infoformat,
01185                 $formatoptions, $this->course->id)), 200);
01186         echo '</span></div></div>';
01187     }
01188 
01189     protected function display_options($recurse, $showhidden, $showquestiontext) {
01190         echo '<form method="get" action="edit.php" id="displayoptions">';
01191         echo "<fieldset class='invisiblefieldset'>";
01192         echo html_writer::input_hidden_params($this->baseurl,
01193                 array('recurse', 'showhidden', 'qbshowtext'));
01194         $this->display_category_form_checkbox('recurse', $recurse,
01195                 get_string('includesubcategories', 'question'));
01196         $this->display_category_form_checkbox('showhidden', $showhidden,
01197                 get_string('showhidden', 'question'));
01198         echo '<noscript><div class="centerpara"><input type="submit" value="' .
01199                 get_string('go') . '" />';
01200         echo '</div></noscript></fieldset></form>';
01201     }
01202 }
01203 
01214 function quiz_print_grading_form($quiz, $pageurl, $tabindex) {
01215     global $OUTPUT;
01216     $strsave = get_string('save', 'quiz');
01217     echo '<form method="post" action="edit.php" class="quizsavegradesform"><div>';
01218     echo '<fieldset class="invisiblefieldset" style="display: block;">';
01219     echo "<input type=\"hidden\" name=\"sesskey\" value=\"" . sesskey() . "\" />";
01220     echo html_writer::input_hidden_params($pageurl);
01221     $a = '<input type="text" id="inputmaxgrade" name="maxgrade" size="' .
01222             ($quiz->decimalpoints + 2) . '" tabindex="' . $tabindex
01223          . '" value="' . quiz_format_grade($quiz, $quiz->grade) . '" />';
01224     echo '<label for="inputmaxgrade">' . get_string('maximumgradex', '', $a) . "</label>";
01225     echo '<input type="hidden" name="savechanges" value="save" />';
01226     echo '<input type="submit" value="' . $strsave . '" />';
01227     echo '</fieldset>';
01228     echo "</div></form>\n";
01229     return $tabindex + 1;
01230 }
01231 
01237 function quiz_print_status_bar($quiz) {
01238     global $CFG;
01239 
01240     $bits = array();
01241 
01242     $bits[] = html_writer::tag('span',
01243             get_string('totalpointsx', 'quiz', quiz_format_grade($quiz, $quiz->sumgrades)),
01244             array('class' => 'totalpoints'));
01245 
01246     $bits[] = html_writer::tag('span',
01247             get_string('numquestionsx', 'quiz', quiz_number_of_questions_in_quiz($quiz->questions)),
01248             array('class' => 'numberofquestions'));
01249 
01250     $timenow = time();
01251 
01252     // Exact open and close dates for the tool-tip.
01253     $dates = array();
01254     if ($quiz->timeopen > 0) {
01255         if ($timenow > $quiz->timeopen) {
01256             $dates[] = get_string('quizopenedon', 'quiz', userdate($quiz->timeopen));
01257         } else {
01258             $dates[] = get_string('quizwillopen', 'quiz', userdate($quiz->timeopen));
01259         }
01260     }
01261     if ($quiz->timeclose > 0) {
01262         if ($timenow > $quiz->timeclose) {
01263             $dates[] = get_string('quizclosed', 'quiz', userdate($quiz->timeclose));
01264         } else {
01265             $dates[] = get_string('quizcloseson', 'quiz', userdate($quiz->timeclose));
01266         }
01267     }
01268     if (empty($dates)) {
01269         $dates[] = get_string('alwaysavailable', 'quiz');
01270     }
01271     $tooltip = implode(', ', $dates);;
01272 
01273     // Brief summary on the page.
01274     if ($timenow < $quiz->timeopen) {
01275         $currentstatus = get_string('quizisclosedwillopen', 'quiz',
01276                 userdate($quiz->timeopen, get_string('strftimedatetimeshort', 'langconfig')));
01277     } else if ($quiz->timeclose && $timenow <= $quiz->timeclose) {
01278         $currentstatus = get_string('quizisopenwillclose', 'quiz',
01279                 userdate($quiz->timeclose, get_string('strftimedatetimeshort', 'langconfig')));
01280     } else if ($quiz->timeclose && $timenow > $quiz->timeclose) {
01281         $currentstatus = get_string('quizisclosed', 'quiz');
01282     } else {
01283         $currentstatus = get_string('quizisopen', 'quiz');
01284     }
01285 
01286     $bits[] = html_writer::tag('span', $currentstatus,
01287             array('class' => 'quizopeningstatus', 'title' => implode(', ', $dates)));
01288 
01289     echo html_writer::tag('div', implode(' | ', $bits), array('class' => 'statusbar'));
01290 }
 All Data Structures Namespaces Files Functions Variables Enumerations