This was started and usability tested as a Finnish Summer of Code project, and then Olli did further work on it in his own time to get it in shape for inclusion in Moodle 2.0. I reviewed all the code. There are a number of minor outstanding issues that will be fixed soon. See the subtasks of MDL-17284 for a list.
The goal of these changes is to:
* help teachers new to Moodle, so when they first see the quiz editing page, they don't go "Huh! What on earth am I supposed to do here?"
* help novice Moodle users understand and learn to use some of the more advanced quiz feature;
* but, without slowing down more experienced quiz users.
Naturally, with ambitous goals like that, we won't have managed to satisy everybody, but I think this change is a big step in the right direction.
There is extensive documentation on this project at http://docs.moodle.org/en/Development:Quiz_UI_redesign.
--- /dev/null
+<h1>Basic ideas of making quizzes</h1>
+<p>The main concepts while managing quiz content (questions) are:</p>
+<ul>
+ <li>Quiz and pages</li>
+ <li>Question bank and its categories</li>
+ <li>Random question</li>
+</ul>
+<p>You can think of a <strong>quiz</strong>, in essence, to be like a
+traditional pen&paper quiz (or an exam/test). It contains questions.
+You can divide the questions in a quiz on several <strong>pages</strong>
+or you can keep them all on one page.
+With Moodle Quiz, you can also give the grading beforehand for the
+questions in a quiz (as well as the total for the entire quiz).</p>
+<p>When you create questions, they are stored in the <strong>Question
+Bank</strong>. In the Question Bank you can create categories, which are similar
+to folders. You can use them to create a hierarchy for organizing
+questions, for example, by topic. When you create a question into
+an exam, a copy of it is stored in the Question Bank. If you decide to
+remove your question from an exam, it will still be intact in the
+question bank until you delete it from there, too.</p>
+<p>You can use <strong>Random Questions</strong>, if you want a question to
+vary between different attempts students make at the quiz (for example,
+to avoid cheating by means of students copying questions to each other).
+Just create a random question in the quiz and add questions in the
+category of the random question.</p>
$string['youneedtoenrol'] = 'You need to enrol in this course before you can attempt this quiz';
$string['yourfinalgradeis'] = 'Your final grade for this quiz is $a.';
$string['zerosignificantfiguresnotallowed'] = 'The correct answer cannot have zero significant figures!';
-
+$string['totalquestionsinrandomqcategory'] = 'Total of $a questions in category.';
+$string['selectquestiontype'] = ' -- Select question type -- ';
+$string['adddescriptionlabel'] = 'Add description/label';
+$string['addrandomquestion'] = 'Add random question';
+$string['addrandomquestiontoquiz'] = 'Add random question to quiz $a';
+$string['parentcategory'] = 'Parent category';
+$string['selectcategory'] = 'Select category';
+$string['createcategoryfornewrandomquestion'] = 'Create a question category for the new random question';
+$string['qname'] = 'name';
+$string['qtypename'] = 'type, name';
+$string['age'] = 'age';
+$string['sortquestionsbyx'] = 'Sort questions by: $a';
+$string['addpagehere'] = 'Add page here';
+$string['questionbankmanagement'] = 'Question Bank management';
+$string['totalpoints'] = 'Total of grades';
+$string['quizwillopen'] = 'This quiz will open $a';
+$string['quizopenwillclose'] = 'This quiz is open, will close on $a at ';
+$string['basicideasofquiz'] = 'Basic ideas of making quizzes';
+$string['noquestionsinquiz'] = 'There are no questions in this quiz.';
+$string['addquestion'] = 'Add question';
+$string['questiontextisempty'] = '[Empty question text]';
+$string['addrandomfromcategory'] = 'Add random questions from category';
+$string['fromcategory'] = 'from category';
+$string['questionbankcontents'] = 'Question Bank contents';
+$string['quizorderrandom'] = '* Order of quiz is shuffled';
+$string['quizordernotrandom'] = 'Order of quiz not shuffled';
+$string['repaginatecommand'] = 'Repaginate';
+$string['orderandpaging'] = 'Order and paging';
+$string['noquestionsonpage'] = 'Empty page';
+$string['orderingquiz'] = 'Order and paging';
+$string['moveselectedonpage'] = 'Move selected questions to page';
+$string['addnewpagesafterselected'] = 'Add new pages after selected questions';
+$string['reorderquestions'] = 'Reorder questions';
+$string['noquestionsnotinuse'] = 'This random question is not in use, since its category is empty.';
+$string['addnewquestionsqbank'] = 'Add questions to the category $a in the \'Question bank contents\' tool >>';
+$string['empty'] = 'Empty';
+$string['quizopened'] = 'This quiz is open.';
+$string['areyousuredeleteselected'] = 'Are you sure you want to delete the selected questions?';
+$string['questionsperpageselected'] = 'Questions per page has been set so the paging is currently fixed. As a result, the paging controls have been disabled. You can change this in ';
+$string['shufflequestionsselected'] = '* Shuffle questions has been set so question order is random. As a result, the button Reorder questions has been disabled. You can change this in ';
?>
* @param mixed $listbox if false, display as a dropdown menu. If true, display as a list box.
* By default, the list box will have a number of rows equal to min(10, count($options)), but if
* $listbox is an integer, that number is used for size instead.
- * @param
+ * @param
*/
function choose_from_menu ($options, $name, $selected='', $nothing='choose', $script='',
$nothingvalue='0', $return=false, $disabled=false, $tabindex=0,
/**
- * Implements a complete little popup form
+ * Implements a complete little form with a dropdown menu. When JavaScript is on
+ * selecting an option from the dropdown automatically submits the form (while
+ * avoiding the usual acessibility problems with this appoach). With JavaScript
+ * off, a 'Go' button is printed.
*
- * @uses $CFG
- * @param string $common The URL up to the point of the variable that changes
- * @param array $options Alist of value-label pairs for the popup list
- * @param string $formid Id must be unique on the page (originaly $formname)
- * @param string $selected The option that is already selected
+ * @param string $baseurl The target URL up to the point of the variable that changes
+ * @param array $options A list of value-label pairs for the popup list
+ * @param string $formid id for the control. Must be unique on the page. Used in the HTML.
+ * @param string $selected The option that is initially selected
* @param string $nothing The label for the "no choice" option
* @param string $help The name of a help page if help is required
* @param string $helptext The name of the label for the help button
- * @param boolean $return Indicates whether the function should return the text
+ * @param boolean $return Indicates whether the function should return the HTML
* as a string or echo it directly to the page being rendered
* @param string $targetwindow The name of the target page to open the linked page in.
* @param string $selectlabel Text to place in a [label] element - preferred for accessibility.
- * @param array $optionsextra TODO, an array?
+ * @param array $optionsextra an array with the same keys as $options. The values are added within the corresponding <option ...> tag.
+ * @param string $submitvalue Optional label for the 'Go' button. Defaults to get_string('go').
+ * @param boolean $disabled If true, the menu will be displayed disabled.
* @return string If $return is true then the entire form is returned as a string.
* @todo Finish documenting this function<br>
*/
-function popup_form($common, $options, $formid, $selected='', $nothing='choose', $help='', $helptext='', $return=false,
-$targetwindow='self', $selectlabel='', $optionsextra=NULL) {
+function popup_form($baseurl, $options, $formid, $selected='', $nothing='choose', $help='', $helptext='', $return=false,
+$targetwindow='self', $selectlabel='', $optionsextra=NULL, $submitvalue='', $disabled=false) {
global $CFG, $SESSION;
static $go, $choose; /// Locally cached, in case there's lots on a page
return '';
}
- if (!isset($go)) {
- $go = get_string('go');
+ if (empty($submitvalue)){
+ if (!isset($go)) {
+ $go = get_string('go');
+ $submitvalue=$go;
+ }
}
-
if ($nothing == 'choose') {
if (!isset($choose)) {
$choose = get_string('choose');
}
$nothing = $choose.'...';
}
+ if ($disabled) {
+ $disabled = 'disabled="disabled"';
+ } else {
+ $disabled = '';
+ }
// changed reference to document.getElementById('id_abc') instead of document.abc
// MDL-7861
$selectlabel = '<label for="'.$formid.'_jump">'.$selectlabel.'</label>';
}
- //IE and Opera fire the onchange when ever you move into a dropdwown list with the keyboard.
+ //IE and Opera fire the onchange when ever you move into a dropdown list with the keyboard.
//onfocus will call a function inside dropdown.js. It fixes this IE/Opera behavior.
//Note: There is a bug on Opera+Linux with the javascript code (first mouse selection is inactive),
//so we do not fix the Opera behavior on Linux
if (check_browser_version('MSIE') || (check_browser_version('Opera') && !check_browser_operating_system("Linux"))) {
- $output .= '<div>'.$selectlabel.$button.'<select id="'.$formid.'_jump" onfocus="initSelect(\''.$formid.'\','.$targetwindow.')" name="jump">'."\n";
+ $output .= '<div>'.$selectlabel.$button.'<select id="'.$formid.'_jump" onfocus="initSelect(\''.$formid.'\','.$targetwindow.')" name="jump" '.$disabled.'>'."\n";
}
//Other browser
else {
- $output .= '<div>'.$selectlabel.$button.'<select id="'.$formid.'_jump" name="jump" onchange="'.$targetwindow.'.location=document.getElementById(\''.$formid.'\').jump.options[document.getElementById(\''.$formid.'\').jump.selectedIndex].value;">'."\n";
+ $output .= '<div>'.$selectlabel.$button.'<select id="'.$formid.'_jump" name="jump" onchange="'.$targetwindow.'.location=document.getElementById(\''.$formid.'\').jump.options[document.getElementById(\''.$formid.'\').jump.selectedIndex].value;" '.$disabled.'>'."\n";
}
if ($nothing != '') {
} else {
if (!empty($CFG->usesid) && !isset($_COOKIE[session_name()]))
{
- $url = $SESSION->sid_process_url( $common . $value );
+ $url = $SESSION->sid_process_url( $baseurl . $value );
} else
{
- $url=$common . $value;
+ $url=$baseurl . $value;
}
$optstr = ' <option value="' . $url . '"';
$output .= '</select>';
$output .= '<input type="hidden" name="sesskey" value="'.sesskey().'" />';
$output .= '<div id="noscript'.$formid.'" style="display: inline;">';
- $output .= '<input type="submit" value="'.$go.'" /></div>';
+ $output .= '<input type="submit" value="'.$submitvalue.'" '.$disabled.' /></div>';
$output .= '<script type="text/javascript">'.
"\n//<![CDATA[\n".
'document.getElementById("noscript'.$formid.'").style.display = "none";'.
$formname = 'theform';
$fieldname = 'message';
}
-
+
$output .= print_js_call('emoticons_help.init', array($formname, $fieldname, 'emoticonlist'), true);
return $output;
* require_once in PHP.
*
* There are two special-case calls to this function from print_header which are
- * internal to weblib and use the second $extracthtmlparameter:
+ * internal to weblib and use the second $extracthtml parameter:
* $extracthtml = 1: this is used before printing the header.
* It returns the script tag code that should go inside the <head>.
* $extracthtml = 2: this is used after printing the header and handles any
* variable, and then just output the configuration variables from PHP using
* this function.
*
- * For example, look at the code in question_init_qenginejs_script() in
+ * For example, look at the code in question_init_qenginejs_script() in
* lib/questionlib.php. It writes out a bunch of $settings like
* 'pixpath' => $CFG->pixpath, with $prefix = 'qengine_config'. This gets output
* in print_header, then the code in question/qengine.js can access these variables
--- /dev/null
+<?php // $Id$
+/**
+ * Fallback page of /mod/quiz/edit.php add random question dialog,
+ * for users who do not use javascript.
+ *
+ * @author Olli Savolainen, as a part of the Quiz UI Redesign project in Summer 2008
+ * {@link http://docs.moodle.org/en/Development:Quiz_UI_redesign}.
+ * @license http://www.gnu.org/copyleft/gpl.html GNU Public License
+ * @package quiz
+ */
+ require_once("../../config.php");
+ require_once($CFG->dirroot.'/mod/quiz/editlib.php');
+ require_once($CFG->dirroot."/question/category_class.php");
+
+ list($thispageurl, $contexts, $cmid, $cm, $quiz, $pagevars) = question_edit_setup('editq', true);
+
+ $defaultcategoryobj = question_make_default_categories($contexts->all());
+ $defaultcategoryid=$defaultcategoryobj->id;
+ $defaultcategorycontext=$defaultcategoryobj->contextid;
+ $defaultcategory="$defaultcategoryid,$defaultcategorycontext";
+
+ $qcobject = new question_category_object(
+ $pagevars['cpage'],
+ $thispageurl,
+ $contexts->having_one_edit_tab_cap('categories'),
+ $defaultcategoryid,
+ $defaultcategory,
+ null,
+ $contexts->having_cap('moodle/question:add'));
+
+ //setting the second parameter of process_randomquestion_formdata to true causes it to redirect on success
+ //TODO: process if returns false?
+ quiz_process_randomquestion_formdata($qcobject,true, $cmid);
+
+ //these params are only passed from page request to request while we stay on this page
+ //otherwise they would go in question_edit_setup
+ $quiz_page = optional_param('quiz_page', 0, PARAM_SEQUENCE);
+ $returnurl = optional_param('returnurl', 0, PARAM_LOCALURL);
+
+ $strquizzes = get_string('modulenameplural', 'quiz');
+ $strquiz = get_string('modulename', 'quiz');
+ $streditingquestions = get_string('editquestions', "quiz");
+ $streditingquiz = get_string('editinga', 'moodle', $strquiz);
+
+ // Get the course object and related bits.
+ if (! $course = $DB->get_record("course", array("id"=> $quiz->course))) {
+ error("This course doesn't exist");
+ }
+ // TODO: Log this visit.
+ /*
+ add_to_log($cm->course, 'quiz', 'editquestions',
+ "view.php?id=$cm->id", "$quiz->id", $cm->id);
+ */
+ //you need mod/quiz:manage in addition to question capabilities to access this page.
+ require_capability('mod/quiz:manage', $contexts->lowest());
+ // Print basic page layout.
+
+ $strupdatemodule = has_capability('moodle/course:manageactivities', $contexts->lowest())
+ ? update_module_button($cm->id, $course->id, get_string('modulename', 'quiz'))
+ : "";
+ $navigation = build_navigation($streditingquiz, $cm);
+ print_header_simple($streditingquiz, '', $navigation, "", "", true, $strupdatemodule);
+
+ if (!$quizname = $DB->get_field($cm->modname, 'name', array('id'=> $cm->instance))) {
+ error('Cannot get the module name in build navigation.');
+ }
+
+ print_heading(get_string("addrandomquestiontoquiz","quiz",$quizname), 'left', 2);
+
+ $qcobject->display_randomquestion_user_interface();
+
+ print_footer($course);
+?>
\ No newline at end of file
--- /dev/null
+/** JavaScript for /mod/quiz/edit.php
+ */
+
+YAHOO.namespace("cats.container");
+YAHOO.namespace("quiz.container");
+function init() {
+ YAHOO.util.Dom.setStyle('randomquestiondialog', 'display', 'block');
+ YAHOO.cats.container.module = new YAHOO.widget.Module("module");
+ YAHOO.cats.container.show = new YAHOO.widget.Module("show");
+ YAHOO.cats.container.hide = new YAHOO.widget.Module("hide");
+ YAHOO.cats.container.module.render();
+ YAHOO.util.Event.addListener("show", "click", YAHOO.cats.container.module.show,
+ YAHOO.cats.container.module, true);
+ YAHOO.util.Event.addListener("show", "click",
+ function(e){
+ YAHOO.cats.container.hide.show;
+ // for some reason YUI sets element display "block" so we have to reverse that:
+ hideel.setStyle("display", "inline");
+ //TODO: get sURL from the phpdata object somehow
+ var sUrl="";
+ var transaction = YAHOO.util.Connect.asyncRequest("GET", sUrl, null, null);
+ YAHOO.util.Event.stopEvent(e);
+ }, YAHOO.cats.container.hide, true);
+ YAHOO.util.Event.addListener("show", "click", YAHOO.cats.container.show.hide, YAHOO.cats.container.show, true);
+ YAHOO.util.Event.addListener("hide", "click", YAHOO.cats.container.module.hide, YAHOO.cats.container.module, true);
+ YAHOO.util.Event.addListener("hide", "click",
+ function(e){
+ YAHOO.cats.container.show.show;
+ // for some reason YUI sets element display
+ // to "block" so we have to reverse that:
+ showel.setStyle("display", "inline");
+ var sUrl="$surl";
+ var transaction = YAHOO.util.Connect.asyncRequest("GET", sUrl, null, null);
+ YAHOO.util.Event.stopEvent(e);
+ }, YAHOO.cats.container.show, true);
+
+ YAHOO.util.Event.addListener("hide", "click", YAHOO.cats.container.hide.hide, YAHOO.cats.container.hide, true);
+
+ // Instantiate the Dialog
+ /* zIndex must be way above 99 to be above the active quiz tab*/
+ YAHOO.quiz.container.randomquestiondialog = new YAHOO.widget.Dialog("randomquestiondialog",
+ {
+ constraintoviewport : true,
+ visible : false,
+ modal:true,
+ width : "100%",
+ iframe:true,
+ zIndex:1000,
+ fixedcenter : true,
+ close: true,
+ draggable: true,
+ dragOnly: true,
+ postmethod: "form"
+
+ } );
+ //show the dialog and depending on from which form (corresponding
+ // a specific quiz page) it was triggered, set the value of the form's
+ // rqpage input element to the form number
+ YAHOO.util.Event.addListener(this.dialog_listeners, "click",
+ function(e){
+ this.show();
+ var rbutton = YAHOO.util.Event.getTarget(e);
+ var rbform = YAHOO.util.Dom.getAncestorByClassName(rbutton,"randomquestionform");
+ //this depends on the fact that the element hierarchy be:
+ // <form class="randomquestionform"><div>[input elements]</div></form>
+ var rbformelements = YAHOO.util.Dom.getChildren
+ (YAHOO.util.Dom.getFirstChild(rbform));
+ var rqpage=YAHOO.util.Dom.get("rform_qpage");
+
+ /*
+ //this should work, it doesn't, no time to debug.
+ var rqpagehiddenel=YAHOO.util.Dom.getFirstChildBy(rbformelements,function(el) {
+ //alert("infunc");
+ var result=YAHOO.util.Dom.hasClass(el,"addonpage_formelement");
+ //if (result) alert ("yes"); else alert("no");
+ return result;
+ });
+ //no element in rqpagehiddenel
+ //rqpage.value=rqpagehiddenel.value.value;
+ */
+
+ //this works instead
+ for (var i = 0; i < rbformelements.length; i++) {
+ if(YAHOO.util.Dom.hasClass(rbformelements[i],"addonpage_formelement")){
+ //why is this not rqpage.value.value, the first "value" being the element property
+ // and the second the value of that property? I don't understand.
+ rqpage.value=rbformelements[i].attributes.value.value;
+ }
+ }
+ YAHOO.util.Event.stopEvent(e);
+ }, YAHOO.quiz.container.randomquestiondialog,
+ YAHOO.quiz.container.randomquestiondialog, true);
+ YAHOO.quiz.container.randomquestiondialog.render();
+// Instantiate the Dialog
+ YAHOO.quiz.container.repaginatedialog = new YAHOO.widget.Dialog("repaginatedialog",
+ {
+ modal:true,
+ width : "100%",
+ iframe:true,
+ zIndex:1000,
+ fixedcenter : true,
+ visible : false,
+ close: true,
+ draggable: true,
+ dragOnly: true,
+ constraintoviewport : true,
+ postmethod: "form"
+ } );
+YAHOO.util.Event.addListener("repaginatecommand", "click",
+ function(e){
+ YAHOO.util.Dom.setStyle('repaginatedialog', 'display', 'block');
+ this.show();
+ }, YAHOO.quiz.container.repaginatedialog,
+ YAHOO.quiz.container.repaginatedialog, true);
+ YAHOO.quiz.container.repaginatedialog.render();
+
+}
+
+
+YAHOO.util.Event.addListener(window, "load", init,phpGenerated,true);
+YAHOO.util.Dom.setStyle('repaginatedialog', 'display', 'block');
+
+//TODO: take this inside the init function to make sure
+//YAHOO.cats.container.module is defined when run
+if (YAHOO.cats.container.module && quiz_qbanktool){
+ YAHOO.cats.container.module.hide();
+ YAHOO.cats.container.show.show();
+ showel.setStyle("display", "inline");
+ YAHOO.cats.container.hide.hide();
+}
*
* @author Martin Dougiamas and many others. This has recently been extensively
* rewritten by Gustav Delius and other members of the Serving Mathematics project
- * {@link http://maths.york.ac.uk/serving_maths}
+ * {@link http://maths.york.ac.uk/serving_maths}. The UI and some functionality
+ * was rewritten as a part of the Quiz UI Redesign project in Summer 2008
+ * {@link http://docs.moodle.org/en/Development:Quiz_UI_redesign}.
* @license http://www.gnu.org/copyleft/gpl.html GNU Public License
* @package quiz
*/
- require_once("../../config.php");
- require_once($CFG->dirroot.'/mod/quiz/editlib.php');
-
- /**
- * Callback function called from question_list() function (which is called from showbank())
- * Displays action icon as first action for each question.
- */
- function module_specific_actions($pageurl, $questionid, $cmid, $canuse){
- global $CFG;
- if ($canuse){
- // for RTL languages: switch right and left arrows /****/
- if (right_to_left()) {
- $movearrow = 'removeright.gif';
- } else {
- $movearrow = 'moveleft.gif';
- }
- $straddtoquiz = get_string("addtoquiz", "quiz");
- $out = "<a title=\"$straddtoquiz\" href=\"edit.php?".$pageurl->get_query_string()."&addquestion=$questionid&sesskey=".sesskey()."\"><img
- src=\"$CFG->pixpath/t/$movearrow\" alt=\"$straddtoquiz\" /></a> ";
- return $out;
+require_once("../../config.php");
+require_once($CFG->dirroot.'/mod/quiz/editlib.php');
+require_once($CFG->dirroot."/question/category_class.php");
+require_js(array('yui_yahoo','yui_dom-event', 'yui_container',
+ 'yui_element','yui_dragdrop','yui_animation', 'yui_logger'));
+
+/**
+ * Callback function called from question_list() function (which is called
+ * from showbank())
+ * Displays action icon as first action for each question.
+ */
+function module_specific_actions($pageurl, $questionid, $cmid, $canuse, $cmoptions){
+ global $CFG;
+ if ($canuse && !$cmoptions->hasattempts){
+ // for RTL languages: switch right and left arrows /****/
+ if (right_to_left()) {
+ $movearrow = 'removeright.gif';
} else {
- return '';
+ $movearrow = 'moveleft.gif';
}
- }
- /**
- * Callback function called from question_list() function (which is called from showbank())
- * Displays button in form with checkboxes for each question.
- */
- function module_specific_buttons($cmid){
- global $THEME;
$straddtoquiz = get_string("addtoquiz", "quiz");
- $out = "<input type=\"submit\" name=\"add\" value=\"{$THEME->larrow} $straddtoquiz\" />\n";
+ $out = "<a title=\"$straddtoquiz\" href=\"edit.php?".
+ $pageurl->get_query_string().
+ "&addquestion=$questionid&sesskey=".
+ sesskey()."\"><img src=\"$CFG->pixpath/t/$movearrow\"
+ alt=\"$straddtoquiz\" /></a> ";
return $out;
+ } else {
+ return '';
+ }
+}
+/**
+ * Callback function called from question_list() function
+ * (which is called from showbank())
+ * Displays button in form with checkboxes for each question.
+ */
+function module_specific_buttons($cmid,$cmoptions){
+ if($cmoptions->hasattempts){
+ $disabled='disabled="disabled"';
+ }else{
+ $disabled='';
}
+ global $THEME;
+ $straddtoquiz = get_string("addtoquiz", "quiz");
+ $out = "<input type=\"submit\" name=\"add\"
+ value=\"{$THEME->larrow} $straddtoquiz\" $disabled />\n";
+ return $out;
+}
- /**
- * Callback function called from question_list() function (which is called from showbank())
- */
- function module_specific_controls($totalnumber, $recurse, $category, $cmid){
- global $QTYPES;
- $out = '';
- $catcontext = get_context_instance_by_id($category->contextid);
- if (has_capability('moodle/question:useall', $catcontext)){
- $randomusablequestions = $QTYPES['random']->get_usable_questions_from_category(
- $category->id, $recurse, '0');
- $maxrand = count($randomusablequestions);
- if ($maxrand > 0) {
- for ($i = 1;$i <= min(10, $maxrand); $i++) {
- $randomcount[$i] = $i;
- }
- for ($i = 20;$i <= min(100, $maxrand); $i += 10) {
- $randomcount[$i] = $i;
- }
- $out .= '<br />';
- $out .= get_string('addrandom', 'quiz', choose_from_menu($randomcount, 'randomcount', '1', '', '', '', true));
- $out .= '<input type="hidden" name="recurse" value="'.$recurse.'" />';
- $out .= '<input type="hidden" name="categoryid" value="'.$category->id.'" />';
- $out .= ' <input type="submit" name="addrandom" value="'. get_string('add') .'" />';
- $out .= helpbutton('random', get_string('random', 'quiz'), 'quiz', true, false, '', true);
+/**
+ * Callback function called from question_list() function
+ * (which is called from showbank())
+ */
+function module_specific_controls($totalnumber, $recurse, $category, $cmid, $cmoptions){
+ global $THEME,$QTYPES;
+ $out = '';
+ $catcontext = get_context_instance_by_id($category->contextid);
+ if (has_capability('moodle/question:useall', $catcontext)){
+ if($cmoptions->hasattempts){
+ $disabled='disabled="disabled"';
+ }else{
+ $disabled='';
+ }
+ $randomusablequestions = $QTYPES['random']->get_usable_questions_from_category(
+ $category->id, $recurse, '0');
+ $maxrand = count($randomusablequestions);
+ if ($maxrand > 0) {
+ for ($i = 1;$i <= min(10, $maxrand); $i++) {
+ $randomcount[$i] = $i;
}
+ for ($i = 20;$i <= min(100, $maxrand); $i += 10) {
+ $randomcount[$i] = $i;
+ }
+ $straddtoquiz = get_string("addtoquiz", "quiz");
+ $out = '<strong><label for="menurandomcount">'.get_string('addrandomfromcategory','quiz').
+ '</label>:</strong><br />';
+ $out .= get_string('addrandom', 'quiz', choose_from_menu($randomcount,
+ 'randomcount', '1', '', '', '', true,$cmoptions->hasattempts));
+ $out .= '<input type="hidden" name="recurse" value="'.$recurse.'" />';
+ $out .= "<input type=\"hidden\" name=\"categoryid\"
+ value=\"$category->id\" />";
+ $out .= ' <input type="submit" name="addrandom" value="'.
+ $straddtoquiz.'" '.$disabled.' />';
+ $out .= helpbutton('random', get_string('random', 'quiz'), 'quiz',
+ true, false, '', true);
}
- return $out;
}
+ return $out;
+}
- list($thispageurl, $contexts, $cmid, $cm, $quiz, $pagevars) = question_edit_setup('editq', true);
-
- //these params are only passed from page request to request while we stay on this page
- //otherwise they would go in question_edit_setup
- $quiz_showbreaks = optional_param('showbreaks', -1, PARAM_BOOL);
- $quiz_reordertool = optional_param('reordertool', 0, PARAM_BOOL);
- if ($quiz_showbreaks > -1) {
- $thispageurl->param('showbreaks', $quiz_showbreaks);
- } else {
- $quiz_showbreaks = get_config('quiz', 'questionsperpage') > 1;
+/**
+ * Add an arbitrary element to array at a specified index, pushing the rest
+ * back.
+ *
+ * @param array $array The array to operate on
+ * @param mixed $value The element to add
+ * @param integer $at The position at which to add the element
+ * @return array
+ */
+function array_add_at($array,$value,$at){
+ $beginpart=array_slice($array, 0,$at);
+ $endpart=array_slice($array, $at, (count($array)-$at) );
+ $beginpart[]=$value;
+ $result=array_merge($beginpart,$endpart);
+ return $result;
+}
+/**
+ * Just like strpos, but it returns the position
+ * of the nth instance of the needle.
+ * Thanks to chasesan at gmail for strpos2
+ * http://www.php.net/manual/en/function.strpos.php
+ */
+function strpos2($haystack, $needle, $nth = 1)
+{
+ //Fixes a null return if the position is at the beginning of input
+ //It also changes all input to that of a string ^.~
+ $haystack = ' '.$haystack;
+ if (!strpos($haystack, $needle)){
+ return false;
}
- if ($quiz_reordertool != 0) {
- $thispageurl->param('reordertool', $quiz_reordertool);
+ $offset=0;
+ for($i = 1; $i < $nth; $i++){
+ $offset = strpos($haystack, $needle, $offset) + 1;
}
+ return strpos($haystack, $needle, $offset) - 1;
+}
+/**
+ * Prints the form for setting a quiz' overall grade
+ */
+function quiz_print_grading_form($quiz, $pageurl, $tabindex){
+ global $USER;
+ $strsave=get_string('save',"quiz");
+ echo "<form method=\"post\" action=\"edit.php\"><div>";
+ echo '<fieldset class="invisiblefieldset" style="display: block;">';
+ echo "<input type=\"hidden\" name=\"sesskey\" value=\"$USER->sesskey\" />";
+ echo $pageurl->hidden_params_out();
+ echo '<label for="inputmaxgrade">'.get_string("maximumgrade")."</label>: ";
+ echo '<input type="text" id="inputmaxgrade" name="maxgrade" size="' . ($quiz->decimalpoints + 2) . '" tabindex="'.($tabindex)
+ .'" value="'.quiz_format_grade($quiz, $quiz->grade).'" />';
+ echo '<input type="hidden" name="savechanges" value="save" />';
+ echo '<input type="submit" value="'.$strsave.'" />';
+ helpbutton("maxgrade", get_string("maximumgrade"), "quiz");
+ echo '</fieldset>';
+ echo "</div></form>\n";
+}
+/**
+ * Print the status bar
+ *
+ * @param mixed $quiz The quiz object of the quiz in question
+ * @param integer $sumgrades The sum of the grades of the quiz to display
+ */
- $strquizzes = get_string('modulenameplural', 'quiz');
- $strquiz = get_string('modulename', 'quiz');
- $streditingquestions = get_string('editquestions', "quiz");
- $streditingquiz = get_string('editinga', 'moodle', $strquiz);
-
- // Get the course object and related bits.
- if (! $course = $DB->get_record('course', array('id' => $quiz->course))) {
- print_error('invalidcourseid', 'error');
+function quiz_print_status_bar($quiz,$sumgrades){
+ global $CFG;
+ $numberofquestions=quiz_number_of_questions_in_quiz($quiz->questions);
+ ?><div class="statusdisplay"><span class="totalpoints">
+ <?php echo get_string("totalpoints","quiz") ?>:</span>
+ <?php echo $sumgrades; ?>
+ | <span class="numberofquestions">
+ <?php
+ echo get_string("questions","quiz").": $numberofquestions"
+ ?></span>
+ | <span class="quizopeningstatus">
+ <?php
+ print_timing_information($quiz,true);
+ ?></span><?php
+ // If questions are shuffled, notify the user about the
+ // question order not making much sense
+
+ $updateurl=new moodle_url("$CFG->wwwroot/course/mod.php",
+ array("return"=>"true","update"=>$quiz->cmid, "sesskey"=>sesskey()));
+ echo '<br /><strong><a href="'.$updateurl->out().'">';
+ print_string('updatethis', '', get_string('modulename', 'quiz'));
+ echo '</a>:</strong> ';
+ if($quiz->shufflequestions){
+ echo "*";
+ }
+ echo get_string("shufflequestions",'quiz').": ";
+ if($quiz->shufflequestions){
+ echo get_string("yes");
+ }
+ else{
+ echo get_string("no");
+ }
+ echo " | ";
+ print_string("questionsperpage","quiz");
+ $questionsperpagebool = ($quiz->questionsperpage < 1) ? 0 : 1;
+ if($questionsperpagebool){
+ echo ": $quiz->questionsperpage";
+ }else{
+ echo ": ".get_string("unlimited");
}
- // Log this visit.
- add_to_log($cm->course, 'quiz', 'editquestions',
+ ?>
+ </div>
+ <?php
+}
+
+
+list($thispageurl, $contexts, $cmid, $cm, $quiz, $pagevars) =
+ question_edit_setup('editq', true);
+
+$defaultcategoryobj = question_make_default_categories($contexts->all());
+$defaultcategoryid=$defaultcategoryobj->id;
+$defaultcategorycontext=$defaultcategoryobj->contextid;
+$defaultcategory="$defaultcategoryid,$defaultcategorycontext";
+//these params are only passed from page request to request while we stay on
+//this page otherwise they would go in question_edit_setup
+$quiz_reordertool = optional_param('reordertool', 0, PARAM_BOOL);
+$quiz_qbanktool = optional_param('qbanktool', -1, PARAM_BOOL);
+if ($quiz_qbanktool > -1) {
+ $thispageurl->param('qbanktool', $quiz_qbanktool);
+ set_user_preference("quiz_qbanktool_open",$quiz_qbanktool);
+} else {
+ $quiz_qbanktool = get_user_preferences("quiz_qbanktool_open",0);
+}
+
+//will be set further down in the code
+$quiz_has_attempts=false;
+
+if ($quiz_reordertool != 0) {
+ $thispageurl->param('reordertool', $quiz_reordertool);
+}
+
+$strquizzes = get_string('modulenameplural', 'quiz');
+$strquiz = get_string('modulename', 'quiz');
+$streditingquestions = get_string('editquestions', "quiz");
+
+//this just does not work for at least finnish, where words are conjugated:
+//$streditingquiz = get_string('editinga', 'moodle', $strquiz);
+$streditingquiz = get_string('editingquiz', 'quiz');
+$strorderingquiz = get_string('orderingquiz', 'quiz');
+$pagetitle=$streditingquiz;
+if($quiz_reordertool){
+ $pagetitle=$strorderingquiz;
+}
+// Get the course object and related bits.
+if (! $course = $DB->get_record('course', array('id' => $quiz->course))) {
+ print_error('invalidcourseid', 'error');
+}
+
+// Log this visit.
+add_to_log($cm->course, 'quiz', 'editquestions',
"view.php?id=$cm->id", "$quiz->id", $cm->id);
- //you need mod/quiz:manage in addition to question capabilities to access this page.
- require_capability('mod/quiz:manage', $contexts->lowest());
-
- if (isset($quiz->instance)
- && empty($quiz->grades)){ // Construct an array to hold all the grades.
- $quiz->grades = quiz_get_all_question_grades($quiz);
- }
+//you need mod/quiz:manage in addition to question capabilities to access
+//this page.
+require_capability('mod/quiz:manage', $contexts->lowest());
+if (isset($quiz->instance)
+&& empty($quiz->grades)){ // Construct an array to hold all the grades.
+ $quiz->grades = quiz_get_all_question_grades($quiz);
+}
+// SECTION: PROCESS COMMANDS //
/// Now, check for commands on this page and modify variables as necessary
- // If any edit action makes a sifnificant change to the structure of the quiz, then we
- // will need to delete all preview attempts.
- $significantchangemade = false;
-
- if (($up = optional_param('up', false, PARAM_INT)) !== false and confirm_sesskey()) { /// Move the given question up a slot
- $questions = explode(",", $quiz->questions);
- if ($up > 0 and isset($questions[$up])) {
- $prevkey = ($questions[$up-1] == 0) ? $up-2 : $up-1;
- $swap = $questions[$prevkey];
- $questions[$prevkey] = $questions[$up];
- $questions[$up] = $swap;
- $quiz->questions = implode(",", $questions);
- // Always have a page break at the end
- $quiz->questions = $quiz->questions . ',0';
- // Avoid duplicate page breaks
- $quiz->questions = str_replace(',0,0', ',0', $quiz->questions);
- if (!$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->instance))) {
- print_error('cannotsavequestion', 'quiz');
- }
- $significantchangemade = true;
+// If any edit action makes a sifnificant change to the structure of the quiz,
+// then we will need to delete all preview attempts.
+$significantchangemade = false;
+if (($up = optional_param('up', false, PARAM_INT)) !== false and
+ confirm_sesskey()) { /// Move the given question up a slot
+ $questions = explode(",", $quiz->questions);
+ if ($up > 0 and isset($questions[$up])) {
+ //$prevkey = ($questions[$up-1] == 0) ? $up-2 : $up-1;
+ $prevkey = $up-1;
+ $swap = $questions[$prevkey];
+ $questions[$prevkey] = $questions[$up];
+ $questions[$up] = $swap;
+ $quiz->questions = implode(",", $questions);
+ $quiz->questions=quiz_clean_layout($quiz->questions);
+ if (!$DB->set_field('quiz', 'questions', $quiz->questions,
+ array('id' => $quiz->instance))) {
+ print_error('cannotsavequestion', 'quiz');
}
+ $significantchangemade = true;
}
-
- if (($down = optional_param('down', false, PARAM_INT)) !== false and confirm_sesskey()) { /// Move the given question down a slot
- $questions = explode(",", $quiz->questions);
- if ($down < count($questions)) {
- $nextkey = ($questions[$down+1] == 0) ? $down+2 : $down+1;
- $swap = $questions[$nextkey];
- $questions[$nextkey] = $questions[$down];
- $questions[$down] = $swap;
- $quiz->questions = implode(",", $questions);
- // Avoid duplicate page breaks
- $quiz->questions = str_replace(',0,0', ',0', $quiz->questions);
- if (!$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->instance))) {
- print_error('cannotsavequestion', 'quiz');
- }
- $significantchangemade = true;
+}
+
+
+if (($down = optional_param('down', false, PARAM_INT)) !== false and
+ confirm_sesskey()) { /// Move the given question down a slot
+ $questions = explode(",", $quiz->questions);
+ if ($down < count($questions)) {
+ //$nextkey = ($questions[$down+1] == 0) ? $down+2 : $down+1;
+ $nextkey = $down+1;
+ $swap = $questions[$nextkey];
+ $questions[$nextkey] = $questions[$down];
+ $questions[$down] = $swap;
+ $quiz->questions = implode(",", $questions);
+ $quiz->questions=quiz_clean_layout($quiz->questions);
+ if (!$DB->set_field('quiz', 'questions', $quiz->questions,
+ array('id' => $quiz->instance))) {
+ print_error('cannotsavequestion', 'quiz');
}
- }
-
- if (($addquestion = optional_param('addquestion', 0, PARAM_INT)) and confirm_sesskey()) { /// Add a single question to the current quiz
- quiz_add_quiz_question($addquestion, $quiz);
$significantchangemade = true;
}
-
- if (optional_param('add', false, PARAM_BOOL) and confirm_sesskey()) { /// Add selected questions to the current quiz
- $rawdata = (array) data_submitted();
- foreach ($rawdata as $key => $value) { // Parse input for question ids
- if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
- $key = $matches[1];
- quiz_add_quiz_question($key, $quiz);
- }
+}
+if (($addquestion = optional_param('addquestion', 0, PARAM_INT)) and
+ confirm_sesskey()) { /// Add a single question to the current quiz
+ $addonpage = optional_param('addonpage',0,PARAM_INT);
+ quiz_add_quiz_question($addquestion, $quiz, $addonpage);
+ $significantchangemade = true;
+}
+
+if (optional_param('add', false, PARAM_BOOL) and
+ confirm_sesskey()) { /// Add selected questions to the current quiz
+ $rawdata = (array) data_submitted();
+ foreach ($rawdata as $key => $value) { // Parse input for question ids
+ if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
+ $key = $matches[1];
+ quiz_add_quiz_question($key, $quiz);
}
- $significantchangemade = true;
}
-
- if (optional_param('addrandom', false, PARAM_BOOL) and confirm_sesskey()) { /// Add random questions to the quiz
- $recurse = optional_param('recurse', 0, PARAM_BOOL);
+ $significantchangemade = true;
+}
+
+$qcobject = new question_category_object(
+ $pagevars['cpage'],
+ $thispageurl,
+ $contexts->having_one_edit_tab_cap('categories'),
+ $defaultcategoryid,
+ $defaultcategory,
+ null,
+ $contexts->having_cap('moodle/question:add'));
+
+$newrandomcategory=quiz_process_randomquestion_formdata($qcobject);
+
+if ((optional_param('addrandom', false, PARAM_BOOL) OR $newrandomcategory)
+ and confirm_sesskey()) {
+ /// Add random questions to the quiz
+ $recurse = optional_param('recurse', 0, PARAM_BOOL);
+ $addonpage = optional_param('addonpage',0,PARAM_INT);
+ if($newrandomcategory){
+ $categoryid = $newrandomcategory;
+ $randomcount = optional_param('randomcount',1, PARAM_INT);
+ }else{
$categoryid = required_param('categoryid', PARAM_INT);
$randomcount = required_param('randomcount', PARAM_INT);
- // load category
- if (! $category = $DB->get_record('question_categories', array('id' => $categoryid))) {
- print_error('invalidcategoryid', 'error');
- }
- $catcontext = get_context_instance_by_id($category->contextid);
- require_capability('moodle/question:useall', $catcontext);
- $category->name = $category->name;
- // Find existing random questions in this category that are not used by any quiz.
- if ($existingquestions = $DB->get_records_sql(
- "SELECT * FROM {question} q
- WHERE qtype = '" . RANDOM . "'
- AND category = ?
- AND " . $DB->sql_compare_text('questiontext') . " = ?
- AND NOT EXISTS (SELECT * FROM {quiz_question_instances} WHERE question = q.id)
- ORDER BY id", array($category->id, $recurse))) {
- // Take as many of these as needed.
- while (($existingquestion = array_shift($existingquestions)) and $randomcount > 0) {
- quiz_add_quiz_question($existingquestion->id, $quiz);
- $randomcount--;
- }
- }
-
- // If more are needed, create them.
- if ($randomcount > 0) {
- $form->questiontext = $recurse; // we use the questiontext field to store the info
- // on whether to include questions in subcategories
- $form->questiontextformat = 0;
- $form->image = '';
- $form->defaultgrade = 1;
- $form->hidden = 1;
- for ($i = 0; $i < $randomcount; $i++) {
- $form->category = "$category->id,$category->contextid";
- $form->stamp = make_unique_id_code(); // Set the unique code (not to be changed)
- $question = new stdClass;
- $question->qtype = RANDOM;
- $question = $QTYPES[RANDOM]->save_question($question, $form, $course);
- if(!isset($question->id)) {
- print_error('cannotinsertrandomquestion', 'quiz');
- }
- quiz_add_quiz_question($question->id, $quiz);
- }
+ }
+ // load category
+ if (! $category = $DB->get_record('question_categories', array('id' => $categoryid))) {
+ print_error('invalidcategoryid', 'error');
+ }
+ $catcontext = get_context_instance_by_id($category->contextid);
+ require_capability('moodle/question:useall', $catcontext);
+ $category->name = $category->name;
+ // Find existing random questions in this category that are
+ // not used by any quiz.
+ if ($existingquestions = $DB->get_records_sql(
+ "SELECT * FROM {question} q
+ WHERE qtype = '" . RANDOM . "'
+ AND category = ?
+ AND " . $DB->sql_compare_text('questiontext') . " = ?
+ AND NOT EXISTS (SELECT * FROM {quiz_question_instances} WHERE question = q.id)
+ ORDER BY id", array($category->id, $recurse))) {
+ // Take as many of these as needed.
+ while (($existingquestion = array_shift($existingquestions))
+ and $randomcount > 0) {
+ quiz_add_quiz_question($existingquestion->id, $quiz, $addonpage);
+ $randomcount--;
}
- $significantchangemade = true;
}
- if (optional_param('repaginate', false, PARAM_BOOL) and confirm_sesskey()) { /// Re-paginate the quiz
- $questionsperpage = optional_param('questionsperpage', $quiz->questionsperpage, PARAM_INT);
- if ($questionsperpage != $quiz->questionsperpage) {
- $quiz->questionsperpage = $questionsperpage;
- if (!$DB->set_field('quiz', 'questionsperpage', $quiz->questionsperpage, array('id' => $quiz->id))) {
- print_error('cannotsavenumberofquestion', 'quiz');
+ // If more are needed, create them.
+ if ($randomcount > 0) {
+ $form->questiontext = $recurse; // we use the questiontext field
+ // to store the info on whether to include
+ // questions in subcategories
+ $form->questiontextformat = 0;
+ $form->image = '';
+ $form->defaultgrade = 1;
+ $form->hidden = 1;
+ for ($i = 0; $i < $randomcount; $i++) {
+ $form->category = "$category->id,$category->contextid";
+ $form->stamp = make_unique_id_code(); // Set the unique
+ //code (not to be changed)
+ $question = new stdClass;
+ $question->qtype = RANDOM;
+ $question = $QTYPES[RANDOM]->save_question($question, $form,
+ $course);
+ if(!isset($question->id)) {
+ print_error('cannotinsertrandomquestion', 'quiz');
}
+ quiz_add_quiz_question($question->id, $quiz, $addonpage);
}
- $quiz->questions = quiz_repaginate($quiz->questions, $quiz->questionsperpage);
- if (!$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id))) {
- print_error('cannotsavelayout', 'quiz');
- }
- $significantchangemade = true;
- }
- if (($delete = optional_param('delete', false, PARAM_INT)) !== false and confirm_sesskey()) { /// Remove a question from the quiz
- quiz_delete_quiz_question($delete, $quiz);
- $significantchangemade = true;
}
- if (optional_param('savechanges', false, PARAM_BOOL) and confirm_sesskey()) {
- /// We need to save the new ordering (if given) and the new grades
- $oldquestions = explode(",", $quiz->questions); // the questions in the old order
- $questions = array(); // for questions in the new order
- $rawgrades = (array) data_submitted();
- unset($quiz->grades);
- foreach ($rawgrades as $key => $value) {
+ $significantchangemade = true;
+}
+$addpagesafterquestions=array();
+if($addnewpagesafterselected=optional_param('addnewpagesafterselected',null)){
+ $rawgrades = (array) data_submitted();
+ foreach ($rawgrades as $key => $value) {
/// Parse input for question -> grades
- if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
- $key = $matches[1];
- $quiz->grades[$key] = $value;
- quiz_update_question_instance($quiz->grades[$key], $key, $quiz->instance);
-
- /// Parse input for ordering info
- } elseif (preg_match('!^o([0-9]+)$!', $key, $matches)) {
- $key = $matches[1];
- // Make sure two questions don't overwrite each other. If we get a second
- // question with the same position, shift the second one along to the next gap.
- while (array_key_exists($value, $questions)) {
- $value++;
- }
- $questions[$value] = $oldquestions[$key];
- }
+ if (preg_match('!^s([0-9]+)$!', $key, $matches)){
+ $addpagesafterquestions[]=$matches[1];
}
+ }
+}
- // If ordering info was given, reorder the questions
- if ($questions) {
- ksort($questions);
- // Make sure that the quiz does not start with a page break.
- while (reset($questions) == '0') {
- array_shift($questions);
- }
- $quiz->questions = implode(",", $questions);
- // Always have a page break at the end
- $quiz->questions = $quiz->questions . ',0';
- // Avoid duplicate page breaks
- while (strpos($quiz->questions, ',0,0')) {
- $quiz->questions = str_replace(',0,0', ',0', $quiz->questions);
- }
- if (!$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->instance))) {
- print_error('cannotsavequestion', 'quiz');
- }
- }
+if ( (($addpage = optional_param('addpage', false, PARAM_INT)) OR
+ !empty($addpagesafterquestions))
+ and confirm_sesskey() ) { /// Move the given question up a slot
- // If rescaling is required save the new maximum
- $maxgrade = optional_param('maxgrade', -1, PARAM_NUMBER);
- if ($maxgrade >= 0) {
- if (!quiz_set_grade($maxgrade, $quiz)) {
- print_error('cannotsetgrade', 'quiz');
- }
- }
+ $questions = explode(",", $quiz->questions);
+
+ $pagebreakid='0';
+ if ($addpage > 0 and isset($questions[$addpage]) ) {
+ $questions=array_add_at($questions,$pagebreakid,$addpage);
$significantchangemade = true;
}
-
-/// Delete any teacher preview attempts if the quiz has been modified
- if ($significantchangemade) {
- $previewattempts = $DB->get_records_select('quiz_attempts',
- 'quiz = ? AND preview = 1', array($quiz->id));
- if ($previewattempts) {
- foreach ($previewattempts as $attempt) {
- quiz_delete_attempt($attempt, $quiz);
- }
+ foreach($addpagesafterquestions as $key=>$questionid){
+ $addpage=array_search($questionid, $questions)+1;
+ if ($addpage > 0 and isset($questions[$addpage]) ) {
+ $pagebreakid='0';
+ $questions=array_add_at($questions,$pagebreakid,$addpage);
+ $significantchangemade = true;
}
}
+ $quiz->questions = implode(",", $questions);
+ $quiz->questions=quiz_clean_layout($quiz->questions);
- question_showbank_actions($thispageurl, $cm);
+ if (!$DB->set_field('quiz', 'questions', $quiz->questions,
+ array('id' => $quiz->instance))) {
+ print_error('cannotsavequestion', 'quiz');
+ }
-/// all commands have been dealt with, now print the page
+}
+if (optional_param('repaginate', false, PARAM_BOOL) and confirm_sesskey()) {
+ // Re-paginate the quiz
+ $questionsperpage = optional_param('questionsperpage',
+ $quiz->questionsperpage, PARAM_INT);
+ $quiz->questions = quiz_repaginate($quiz->questions,
+ $questionsperpage );
+ if (!$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->id))) {
+ print_error('cannotsavelayout', 'quiz');
+ }
+ $significantchangemade = true;
+}
- // Print basic page layout.
- if (isset($quiz->instance) and $DB->record_exists_select('quiz_attempts', "quiz = ? AND preview = '0'", array($quiz->instance))){
- // one column layout with table of questions used in this quiz
- $strupdatemodule = has_capability('moodle/course:manageactivities', $contexts->lowest())
- ? update_module_button($cm->id, $course->id, get_string('modulename', 'quiz'))
- : "";
- $navigation = build_navigation($streditingquiz, $cm);
- print_header_simple($streditingquiz, '', $navigation, "", "",
- true, $strupdatemodule);
- $currenttab = 'edit';
- $mode = 'editq';
+if ((($deleteemptypage = optional_param('deleteemptypage', false, PARAM_INT))
+ !==false) and confirm_sesskey()) {
+ $questions = explode(",", $quiz->questions);
+ if($deleteemptypage>0){
+ //it points to a value one too big due to the display logic
+ $deleteemptypage--;
+ }
+ if( ((int)$questions[$deleteemptypage]) == 0 ){
+ $questions = explode(",", $quiz->questions);
+ $endpart=array_slice($questions,$deleteemptypage+1,null,true);
+ $beginpart=array_slice($questions,0,$deleteemptypage,true);
+ $questions=array_merge($beginpart,$endpart);
+ $quiz->questions = implode(",", $questions);
+ $quiz->questions=quiz_clean_layout($quiz->questions);
+ }
+ if (!$DB->set_field('quiz', 'questions', $quiz->questions,
+ array('id' => $quiz->instance))) {
+ print_error('cannotsavequestion', 'quiz');
+ }
- include('tabs.php');
- print_box_start();
+}
+$deletequestions=array();
+if($quizdeleteselected=optional_param('quizdeleteselected',false)){
+ $rawgrades = (array) data_submitted();
+ foreach ($rawgrades as $key => $value) {
+ /// Parse input for question -> grades
+ if (preg_match('!^s([0-9]+)$!', $key, $matches)){
+ $deletequestions[]=$matches[1];
+ }
+ }
+}
- echo "<div class=\"quizattemptcounts\">\n";
- echo '<a href="report.php?mode=overview&id=' . $cm->id . '">' .
- quiz_num_attempt_summary($quiz, $cm) . '</a><br />' .
- get_string('cannoteditafterattempts', 'quiz');
- echo "</div>\n";
- $sumgrades = quiz_print_question_list($quiz, $thispageurl, false, $quiz_showbreaks, $quiz_reordertool);
- if (!$DB->set_field('quiz', 'sumgrades', $sumgrades, array('id' => $quiz->instance))) {
- print_error('cannotsetsumgrades', 'quiz');
+if ( (($delete = optional_param('delete', false, PARAM_INT)) !== false OR
+ !empty($deletequestions)) and confirm_sesskey() ) {
+
+ //was: if ($delete > 0 ) {
+ if ($delete !==false) {
+ quiz_delete_quiz_question($delete, $quiz);
+ $significantchangemade = true;
+ }
+ foreach($deletequestions as $key=>$questionid){
+ $questions = explode(",", $quiz->questions);
+ $delete=array_search($questionid, $questions);
+ if ($delete !== false) {
+ quiz_delete_quiz_question($delete, $quiz);
+ $significantchangemade = true;
}
+ }
+ $quiz->questions=quiz_clean_layout($quiz->questions);
- print_box_end();
- print_footer($course);
- exit;
+ if (!$DB->set_field('quiz', 'questions', $quiz->questions,
+ array('id' => $quiz->instance))) {
+ print_error('cannotsavequestion', 'quiz');
}
- // two column layout with quiz info in left column
- $strupdatemodule = has_capability('moodle/course:manageactivities', $contexts->lowest())
- ? update_module_button($cm->id, $course->id, get_string('modulename', 'quiz'))
- : "";
- $navigation = build_navigation($streditingquiz, $cm);
- print_header_simple($streditingquiz, '', $navigation, "", "", true, $strupdatemodule);
+}
+
+if (optional_param('savechanges', false, PARAM_BOOL) and confirm_sesskey()) {
+ $oldquestions = explode(",", $quiz->questions); // the questions in the old order
+ $questions = array(); // for questions in the new order
+ $rawgrades = (array) data_submitted();
+ $moveonpagequestions = array();
+ $moveselectedonpage=0;
+ //TODO: Tim: since we are not submitting all of the grades at once in quiz
+ // UI redesign, we cannot unset it since then we could not display it.
+ //Is there really a need to get rid of the old data here?
+ //unset($quiz->grades);
+ $moveselectedonpagetop=optional_param("moveselectedonpagetop",0,PARAM_INT);
+ $moveselectedonpagebottom=optional_param("moveselectedonpagebottom",0,
+ PARAM_INT);
+ if($moveselectedonpagetop){
+ $moveselectedonpage=$moveselectedonpagetop;
+ }else if($moveselectedonpagebottom){
+ $moveselectedonpage=$moveselectedonpagebottom;
+ }
- $currenttab = 'edit';
- $mode = 'editq';
+ foreach ($rawgrades as $key => $value) {
+ if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
+ /// Parse input for question -> grades
+ $key = $matches[1];
+ $quiz->grades[$key] = $value;
+ quiz_update_question_instance($quiz->grades[$key], $key,
+ $quiz->instance);
- include('tabs.php');
+ } elseif (preg_match('!^o([0-9]+)$!', $key, $matches)) {
+ /// Parse input for ordering info
+ $key = $matches[1];
+ // Make sure two questions don't overwrite each other.
+ // If we get a second
+ // question with the same position, shift the second one
+ // along to the next gap.
+ while (array_key_exists($value, $questions)) {
+ $value++;
+ }
+ $questions[$value] = $oldquestions[$key];
+ } elseif (preg_match('!^s([0-9]+)$!', $key, $matches)){
+ // Parse input for selected questions
+ // (add new pages after questions in quiz)
+ $key = $matches[1];
+ if($moveselectedonpage){
+ $moveonpagequestions[]=$key;
+ }
+ }
+ }
+ // If ordering info was given, reorder the questions
+ if ($questions) {
+ ksort($questions);
+ $quiz->questions = implode(",", $questions);
+ $quiz->questions .=",0";
+ $quiz->questions=quiz_clean_layout($quiz->questions);
- echo '<table border="0" style="width:100%" cellpadding="2" cellspacing="0">';
- echo '<tr><td style="width:50%" valign="top">';
- print_box_start('generalbox quizquestions');
- print_heading(get_string('questionsinthisquiz', 'quiz'), '', 2);
+ }
+ //get a list of questions to move, later to be added in the appropriate
+ //place in the string
+ $questionstomove = implode(",", $moveonpagequestions);
+ if($moveonpagequestions){
+ $pagecount=quiz_number_of_pages($quiz->questions);
+ if($moveselectedonpage>quiz_number_of_pages($quiz->questions)){
+ $moveselectedonpage=$pagecount;
+ }
+ $selectedpageend=(strpos2($quiz->questions,",0",$moveselectedonpage));
+ if($selectedpageend!==FALSE){
+ foreach($moveonpagequestions as $page=>$question){
+ $quiz->questions=str_replace("$question,","",$quiz->questions);
+ }
+ if($moveselectedonpage>1){
+ $pagecount=quiz_number_of_pages($quiz->questions);
+ if($moveselectedonpage>quiz_number_of_pages($quiz->questions)){
+ $moveselectedonpage=$pagecount;
+ }
+ $selectedpageend=(strpos2($quiz->questions,",0",
+ $moveselectedonpage-1));
+ $start=substr($quiz->questions,0,$selectedpageend+1);
+ $end=substr($quiz->questions,$selectedpageend);
+ $quiz->questions=$start.$questionstomove.$end;
+ }else if ($moveselectedonpage==1){
+ $quiz->questions=$questionstomove.",".$quiz->questions;
+ }
+ }else{
+ //TODO: add alert message
+ }
- $sumgrades = quiz_print_question_list($quiz, $thispageurl, true, $quiz_showbreaks, $quiz_reordertool);
- if (!$DB->set_field('quiz', 'sumgrades', $sumgrades, array('id' => $quiz->instance))) {
- print_error('cannotsetsumgrades', 'quiz');
+ }
+ if($moveonpagequestions or $questions){
+ if (!$DB->set_field('quiz', 'questions', $quiz->questions,
+ array('id' => $quiz->instance))) {
+ print_error('cannotsavequestion', 'quiz');
+ }
+ }
+ // If rescaling is required save the new maximum
+ $maxgrade = optional_param('maxgrade', -1, PARAM_NUMBER);
+ if ($maxgrade >= 0) {
+ if (!quiz_set_grade($maxgrade, $quiz)) {
+ print_error('cannotsetgrade', 'quiz');
+ }
}
- print_box_end();
- echo '</td><td style="width:50%" valign="top">';
- question_showbank('editq', $contexts, $thispageurl, $cm, $pagevars['qpage'], $pagevars['qperpage'], $pagevars['qsortorder'], $pagevars['qsortorderdecoded'],
- $pagevars['cat'], $pagevars['recurse'], $pagevars['showhidden'], $pagevars['showquestiontext']);
+ $significantchangemade = true;
+}
+/// Delete any teacher preview attempts if the quiz has been modified
+if ($significantchangemade) {
+ $previewattempts = $DB->get_records_select('quiz_attempts',
+ 'quiz = ? AND preview = 1', array($quiz->id));
+ if ($previewattempts) {
+ foreach ($previewattempts as $attempt) {
+ quiz_delete_attempt($attempt, $quiz);
+ }
+ }
+ redirect($qcobject->pageurl->out());
+}
- echo '</td></tr>';
- echo '</table>';
+question_showbank_actions($thispageurl, $cm);
- print_footer($course);
+/// all commands have been dealt with, now print the page
+$questionbankmanagement='<a href="'.$CFG->wwwroot.
+ '/question/edit.php?courseid='.$course->id.'">'.
+ get_string("questionbankmanagement","quiz").'</a> ';
+
+if (isset($quiz->instance) and $DB->record_exists_select('quiz_attempts',
+ "quiz = ? AND preview = '0'", array($quiz->instance))){
+ $quiz_has_attempts=true;
+}
+
+
+$strupdatemodule = has_capability('moodle/course:manageactivities',
+ $contexts->lowest()) ?
+ update_module_button($cm->id, $course->id,
+ get_string('modulename', 'quiz')) :
+ "";
+$navigation = build_navigation($pagetitle, $cm);
+$localcss= '<link rel="stylesheet" type="text/css" href="edit_redesign.css" />
+ <link rel="stylesheet" type="text/css" href="'.$CFG->wwwroot.
+ '/lib/yui/container/assets/container.css" />';
+
+//Thanks to
+//http://vani.vox.com/library/post/yui-simple-showhide-div-using-module.html
+//as soon as javascript toggling and saving the state to the server as an ajax call
+//has been done, add $quiz_hide_javascript to $localjs
+/*$quiz_hide_javascript="";
+if(!$quiz_qbanktool){
+ $quiz_hide_javascript='var quiz_qbanktool=true;';
+}else{
+ $quiz_hide_javascript='var quiz_qbanktool=false;';
+}*/
+$quiz_randomquestion_dialog_listeners='this.dialog_listeners=[';
+if(($numberoflisteners=quiz_number_of_pages($quiz->questions))==0){
+ $numberoflisteners=1;
+}
+for($page_iter=1;$page_iter<=$numberoflisteners;$page_iter++){
+ if($page_iter!=1){
+ $quiz_randomquestion_dialog_listeners.= ',';
+ }
+ $quiz_randomquestion_dialog_listeners.= '"addrandomdialoglaunch_'.
+ $page_iter.'"';
+}
+$quiz_randomquestion_dialog_listeners.='];';
+$surl=$thispageurl->out(false,array('qbanktool'=>'0'));
+$surl_js="this.sUrl=\"$surl\";";
+$localjs= '<script type="text/javascript" charset="utf-8">
+ function phpdata(){
+ '.$quiz_randomquestion_dialog_listeners.'
+ '.$surl_js.'
+ }
+ var phpGenerated=new phpdata();
+ </script>
+ <script type="text/javascript" src="'.$CFG->wwwroot.
+ '/mod/quiz/edit.js" charset="utf-8"></script>
+';
+//apply CSS for when javascript is enabled
+require_js('mod/quiz/editcss.js',true);
+print_header_simple($pagetitle, '', $navigation, "", $localcss,true,
+ $questionbankmanagement.$strupdatemodule);
+echo $localjs;
+$mode = 'editq';
+$currenttab="edit";
+if($quiz_reordertool){
+ $mode="reorder";
+}
+include('tabs.php');
+
+if($quiz_qbanktool){
+ $showbank_inlinecss='display: none;';
+ $bank_inlinecss='display: block;';
+ $hidebank_inlinecss='display: inline;';
+ $quizcontents_inlinecss="";
+
+}else{
+ $showbank_inlinecss='display: inline;';
+ $bank_inlinecss='display: none;';
+ $hidebank_inlinecss='display: none;';
+ $quizcontents_inlinecss='width:100%;';
+}
+print_side_block_start(get_string('questionbankcontents','quiz').
+ ' <a href="'.
+$thispageurl->out(false,array('qbanktool'=>'1')).
+ '" style="'.$showbank_inlinecss.'" >['.get_string("show").
+ ']</a><!-- id="show" -->
+ <a href="'.$thispageurl->out(false,array('qbanktool'=>'0')).
+ '" style="'.$hidebank_inlinecss.'">['.get_string("hide").
+ ']</a><!-- id="hide" -->
+ ', array("class"=>"questionbankwindow"));
+echo '<div class="container" style="'.$bank_inlinecss.'">';
+echo '<div id="module" class="module">';
+echo '<div class="bd">';
+$cmoptions = new stdClass;
+$cmoptions->hasattempts=$quiz_has_attempts;
+quiz_question_showbank('editq', $contexts, $thispageurl, $cm,
+ $pagevars['qpage'],
+ $pagevars['qperpage'], $pagevars['qsortorder'],
+ $pagevars['qsortorderdecoded'],
+ $pagevars['cat'], $pagevars['recurse'], $pagevars['showhidden'],
+ $pagevars['showquestiontext'],$cmoptions);
+echo '</div> <!-- end .bd -->';
+echo '</div> <!-- end .module -->';
+echo '</div> <!-- end .container -->';
+print_side_block_end();
+
+if (!$quizname = $DB->get_field($cm->modname, 'name', array('id'=>$cm->instance))) {
+ print_error('cannotmodulename');
+}
+
+echo '<div class="quizcontents" id="quizcontentsblock" style="'.$quizcontents_inlinecss.'">';
+$questionsperpagebool = ($quiz->questionsperpage < 1) ? 0 : 1;
+if($questionsperpagebool){
+ $repaginatingdisabledhtml='disabled="disabled"';
+ $repaginatingdisabled=true;
+}else{
+ $repaginatingdisabledhtml='';
+ $repaginatingdisabled=false;
+}
+if($quiz_reordertool){
+ echo '<div class="repaginatecommand"><button id="repaginatecommand" '.$repaginatingdisabledhtml.'>'.
+ get_string("repaginatecommand","quiz").'...</button>';
+ echo '</div>';
+}
+print_heading($pagetitle.": ".$quizname, 'left', 2);
+helpbutton("editconcepts", get_string("basicideasofquiz","quiz"), "quiz",
+ true,get_string("basicideasofquiz","quiz"));
+
+$notifystring="";
+if($quiz_has_attempts){
+ $string=get_string('cannoteditafterattempts', 'quiz');
+ $string.='<br /><a href="report.php?mode=overview&id=' . $cm->id . '">' .
+ quiz_num_attempt_summary($quiz, $cm) . '</a><br />' ;
+ $notifystring.=notify($string,$style='notifyproblem', $align='center', $return=true);
+}
+if($questionsperpagebool && $quiz_reordertool){
+ $string=get_string('questionsperpageselected', 'quiz');
+ $updateurl=new moodle_url("$CFG->wwwroot/course/mod.php",
+ array("return"=>"true","update"=>$quiz->cmid, "sesskey"=>sesskey()));
+ $string.= '<a href="'.$updateurl->out().'">';
+ $string.=get_string('updatethis', '', get_string('modulename', 'quiz'));
+ $string.='</a>.';
+ $notifystring.=notify($string,$style='notifyproblem', $align='center', $return=true);
+}
+if($quiz->shufflequestions && $quiz_reordertool){
+ $string=get_string('shufflequestionsselected', 'quiz');
+ $updateurl=new moodle_url("$CFG->wwwroot/course/mod.php",
+ array("return"=>"true","update"=>$quiz->cmid, "sesskey"=>sesskey()));
+ $string.= '<a href="'.$updateurl->out().'">';
+ $string.=get_string('updatethis', '', get_string('modulename', 'quiz'));
+ $string.='</a>.';
+ $notifystring.=notify($string,$style='notifyproblem', $align='center', $return=true);
+}
+if(!empty($notifystring)){
+ //TODO: make the box closable so it is not in the way
+ print_box_start();
+ echo $notifystring;
+ print_box_end();
+}
+
+if($quiz_reordertool){
+ $perpage= array();
+ $perpage[0] = get_string('allinone', 'quiz');
+ for ($i=1; $i<=50; ++$i) {
+ $perpage[$i] = $i;
+ }
+ $gostring=get_string('go');
+ echo '<div id="repaginatedialog"><div class="hd">';
+ echo get_string("repaginatecommand","quiz");
+ echo '</div><div class="bd">';
+ echo '<form action="edit.php" method="post">';
+ echo '<fieldset class="invisiblefieldset">';
+ echo $thispageurl->hidden_params_out();
+ echo '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />';
+ //YUI does not submit the value of the submit button so
+ //we need to add the value:
+ echo '<input type="hidden" name="repaginate" value="'.$gostring.'" />';
+ print_string('repaginate', 'quiz',
+ choose_from_menu($perpage, 'questionsperpage',
+ $quiz->questionsperpage, '', '', '', true,$repaginatingdisabled));
+ echo '<div class="quizquestionlistcontrols">';
+ echo ' <input type="submit" name="repaginate" value="'. $gostring .'" '.$repaginatingdisabledhtml.' />';
+ echo '</div></fieldset></form></div></div>';
+}
+ob_start();
+$sumgrades = quiz_print_question_list($quiz, $thispageurl, true,
+ null,
+ $quiz_reordertool, $quiz_qbanktool, $quiz_has_attempts);
+
+if (!$DB->set_field('quiz', 'sumgrades', $sumgrades, array('id' => $quiz->instance))) {
+ print_error('cannotsetsumgrades', 'quiz');
+}
+
+$question_list=ob_get_contents();
+ob_end_clean();
+$tabindex=0;
+
+if(!$quiz_reordertool){
+ quiz_print_grading_form($quiz,$thispageurl,$tabindex);
+}
+quiz_print_status_bar($quiz,$sumgrades);
?>
+<div class="<?php echo $currenttab; ?>">
+<?php echo $question_list; ?>
+</div>
+<?php
+//close <div class="quizcontents">:
+echo '</div>';
+
+if(!$quiz_reordertool){
+ // display category adding UI
+ ?>
+<div id="randomquestiondialog">
+<div class="hd"><?php print_string("addrandomquestiontoquiz","quiz",$quizname); ?>
+<span id="pagenumber"><!-- TODO: insert pagenumber here via javascript -->
+</span>
+</div>
+<div class="bd"><?php
+$qcobject->display_randomquestion_user_interface();
+?></div>
+</div>
+ <?php
+}
+print_footer($course);
+?>
\ No newline at end of file
--- /dev/null
+/** JavaScript for /mod/quiz/edit.php to be loaded in the header
+ * Adds a CSS class to display edit.php for users with JavaScript.
+ */
+ YAHOO.util.Event.onDOMReady(
+ function(){
+ YAHOO.util.Dom.addClass('quizcontentsblock', 'usejs');
+ });
\ No newline at end of file
$question = $questions[$id];
unset($questions[$id]);
- // If we deleted the question at the top and it was followed by
- // a page break then delete page break as well
- if ($id == 0 && count($questions) > 1 && $questions[1] == 0) {
- unset($questions[1]);
- }
$quiz->questions = implode(",", $questions);
- // Avoid duplicate page breaks
- $quiz->questions = str_replace(',0,0', ',0', $quiz->questions);
// save new questionlist in database
if (!$DB->set_field('quiz', 'questions', $quiz->questions, array('id' => $quiz->instance))) {
print_error('cannotsavequestion', 'quiz');
* @param object $quiz The extended quiz object as used by edit.php
* This is updated by this function
*/
-function quiz_add_quiz_question($id, &$quiz) {
+function quiz_add_quiz_question($id, &$quiz, $page=0) {
global $DB;
$questions = explode(",", $quiz->questions);
-
if (in_array($id, $questions)) {
return false;
}
$end = end($breaks);
$last = prev($breaks);
$last = $last ? $last : -1;
- if (!$quiz->questionsperpage or (($end - $last -1) < $quiz->questionsperpage)) {
+ if (!$quiz->questionsperpage or
+ (($end - $last -1) < $quiz->questionsperpage)) {
array_pop($questions);
}
}
- // add question
- $questions[] = $id;
- // add ending page break
- $questions[] = 0;
+ if(is_int($page) && $page >= 1){
+ $numofpages=quiz_number_of_pages($quiz->questions);
+ if ($numofpages<$page){
+ //the page specified does not exist in quiz
+ $page=0;
+ }else{
+ // add ending page break - the following logic requires doing
+ //this at this point
+ $questions[] = 0;
+ $currentpage=1;
+ $addnow=false;
+ foreach ($questions as $question){
+ if($question==0){
+ $currentpage++;
+ //The current page is the one after the one we want to add on,
+ //so we add the question before adding the current page.
+ if ($currentpage==$page+1){
+ $questions_new[]=$id;
+ }
+ }
+ $questions_new[]=$question;
+ }
+ $questions=$questions_new;
+ }
+ }
+ if ($page==0){
+ // add question
+ $questions[] = $id;
+ // add ending page break
+ $questions[] = 0;
+ }
// Save new questionslist in database
$quiz->questions = implode(",", $questions);
}
/**
-* Prints a list of quiz questions in a small layout form with knobs
+* 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 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
+* @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, moodle_url $pageurl, $allowdelete=true, $showbreaks=true, $reordertool=false) {
+//TODO: Tim? remove showbreaks since it is no longer used
+function quiz_print_question_list($quiz, $pageurl, $allowdelete=true,
+ $showbreaks=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");
- $strsavegrades = get_string("savegrades", "quiz");
+ $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) {
+ /*if (!$quiz->questions) {
echo "<p class=\"quizquestionlistcontrols\">";
print_string("noquestions", "quiz");
echo "</p>";
return 0;
- }
-
- list($usql, $params) = $DB->get_in_or_equal(explode(',', $quiz->questions));
- if (!$questions = $DB->get_records_sql("SELECT q.*,c.contextid
+ }*/
+ if($quiz->questions){
+ list($usql, $params) = $DB->get_in_or_equal(explode(',', $quiz->questions));
+ $questions = $DB->get_records_sql("SELECT q.*,c.contextid
FROM {question} q,
{question_categories} c
WHERE q.id $usql
- AND q.category = c.id", $params)) {
- echo "<p class=\"quizquestionlistcontrols\">";
- print_string("noquestions", "quiz");
- echo "</p>";
- return 0;
+ AND q.category = c.id", $params);
+ }
+ // if user only has empty pages we have to keep that: out with OR (!$questions)
+ if (!$quiz->questions) {
+ $pagecount=1;
+ echo '<div class="quizpage"><span class="pagetitle">Page '.
+ $pagecount.'</span><div class="pagecontent"><div class="pagestatus">';
+ print_string("noquestionsinquiz", "quiz");
+ echo '</div>';
+ if(!$reordertool){
+ quiz_print_pagecontrols($quiz, $pageurl, $pagecount,$hasattempts);
+ }
+ echo "</div></div></div>";
+ //this is how it worked before summer 2008
+ //OR !$questions
+ if(!isset($questions)){
+ return 0;
+ }
}
- $count = 0;
- $qno = 1;
- $sumgrade = 0;
- $order = explode(',', $quiz->questions);
+
+ $layout=quiz_clean_layout($quiz->questions);
+ $order = explode(',', $layout);
$lastindex = count($order)-1;
- // If the list does not end with a pagebreak then add it on.
- if ($order[$lastindex] != 0) {
- $order[] = 0;
- $lastindex++;
+
+ if ($hasattempts){
+ $disabled='disabled="disabled"';
+ $movedisabled='';
+ $pagingdisabled='';
+ }else{
+ $disabled='';
+ $movedisabled='';
+ $pagingdisabled='';
+ }
+ if($quiz->shufflequestions){
+ $movedisabled='disabled="disabled"';
+ }
+ if($quiz->questionsperpage){
+ $pagingdisabled='disabled="disabled"';
}
- 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";
- // for RTL languages: switch right and left arrows /****/
- if (right_to_left()) {
- $movearrow = 'moveleft.gif';
- } else {
- $movearrow = 'removeright.gif';
+ $reordercontrolssetdefaultsubmit='<div style="display:none;">'.
+ '<input type="submit" name="savechanges" value="'.
+ $strreorderquestions.'" '.$movedisabled.' /></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("areyousuredeleteselected","quiz").'")\'; value="'.
+ get_string("deleteselected").'" '.$disabled.' /></div>';
+
+ $reordercontrols2top='<div class="moveselectedonpage">'.
+ get_string("moveselectedonpage","quiz") .
+ ': <input name="moveselectedonpagetop" type="text" size="2" '.
+ $movedisabled.' />'.
+ '<input type="submit" name="savechanges" value="'.
+ $strmove.'" '.$movedisabled.' />'.'
+ <br /><input type="submit" name="savechanges" value="'.
+ $strreorderquestions.'" '.$movedisabled.' /></div>';
+ $reordercontrols2bottom='<div class="moveselectedonpage">'.
+ '<input type="submit" name="savechanges" value="'.
+ $strreorderquestions.'" '.$movedisabled.' /><br />'.
+ get_string("moveselectedonpage","quiz") .
+ ': <input name="moveselectedonpagebottom" type="text" size="2" '.
+ $movedisabled.' />'.'<input type="submit" name="savechanges" value="'.
+ $strmove.'" '.$movedisabled.' /> '.'</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="'.$USER->sesskey.'" />';
+
+ echo $reordercontrolstop;
}
+ /* // Tim: is this a separate case from the above "no questions in quiz"? Should it still be done?:
+ if(!$quiz->questions){
+ $pagecount=1;
+ echo '<div class="quizpage"><span class="pagetitle">Page '.
+ $pagecount.'</span><div class="pagecontent">';
+ print_string("noquestions", "quiz");
+ quiz_print_pagecontrols($quiz, $pageurl, $pagecount);
+ echo "</div></div>";
+
+ }*/
+
+ //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 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';
}
+ $deletex="delete.gif";
+ if($qnum!=0 OR ($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 a consequent 0 (signaling empty page), tell
+ // the user the page is empty
+ echo '<div class="pagestatus">';
+ print_string("noquestionsonpage", "quiz");
+ echo '</div>';
+ if ($allowdelete && !$hasattempts) { // remove from quiz, not question delete.
+ echo '<div class="quizpagedelete">';
+ echo "<a title=\"$strremove\" href=\"".
+ $pageurl->out_action(array('deleteemptypage'=>$i)).
+ "\"><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
- // 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>';
+
+ /* Display question start */
+?>
+<div class="question">
+ <div class="questioncontainer">
+ <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 OR ($reordertool && $questioncount>99)){
+ $questioncountstring=
+ "$reordercheckboxlabel<small>$questioncount</small>".
+ $reordercheckboxlabelclose.$reordercheckbox;
+ }else{
+ $questioncountstring=$reordercheckboxlabel.$questioncount.
+ $reordercheckboxlabelclose.$reordercheckbox;
+ }
+ echo $questioncountstring;
+ $qno += $question->length;
} else {
- echo '<tr><td><input type="hidden" name="o'.$i.'" size="2" value="'.(10*$count+10).'" /></td>';
+ echo "$reordercheckboxlabel * $reordercheckboxlabelclose".
+ " $reordercheckbox";
}
- } 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
- src=\"$CFG->pixpath/t/up.gif\" class=\"iconsmall\" alt=\"$strmoveup\" /></a>";
+
+ ?>
+ </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'=>$count))."\"><img
+ src=\"$CFG->pixpath/t/up.gif\" class=\"iconsmall
+ $upbuttonclass\" alt=\"$strmoveup\" /></a>";
}
- echo ' ';
- if ($count < $lastindex) {
- echo "<a title=\"$strmovedown\" href=\"".$pageurl->out_action(array('down'=>$count))."\"><img
- src=\"$CFG->pixpath/t/down.gif\" class=\"iconsmall\" alt=\"$strmovedown\" /></a>";
- echo "<a title=\"$strremove\" href=\"".$pageurl->out_action(array('delete'=>$count))."\">
- <img src=\"$CFG->pixpath/t/delete.gif\" class=\"iconsmall\" alt=\"$strremove\" /></a>";
+ }
+ if ($count < $lastindex-1) {
+ if(!$hasattempts){
+ echo "<a title=\"$strmovedown\" href=\"".
+ $pageurl->out_action(array('down'=>$count))."\"><img
+ src=\"$CFG->pixpath/t/down.gif\" class=\"iconsmall\"".
+ " alt=\"$strmovedown\" /></a>";
}
- echo '</td></tr></table></td>';
- echo '<td colspan="2"> </td>';
+ }else{
}
- $count++;
- // missing </tr> here, if loop is broken, need to close the </tr>
- echo "</tr>";
- continue;
- }
- $question = $questions[$qnum];
+ 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('delete'=>$count))."\">
+ <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>
+ <label for="<?php echo "inputq$qnum" ?>"><?php echo $strgrade; ?></label>:<br />
+ <fieldset class="invisiblefieldset" style="display: block;">
+ <input type="hidden" name="sesskey" value="<?php echo $USER->sesskey ?>" />
+ <?php echo $pageurl->hidden_params_out(); ?>
+ <input type="hidden" name="savechanges" value="save" />
+ <?php
+ echo '<input type="text" name="q'.$qnum.'" size="' . ($quiz->decimalpoints + 2) . '"
+ value="'.(0 + $quiz->grades[$qnum]).
+ '" tabindex="'.($lastindex+$qno).'" '.$disabled.' />';
+ ?>
+ <input type="submit" class="pointssubmitbutton" value="<?php echo $strsave; ?>" <?php echo $disabled; ?> />
+ </fieldset>
- echo "<td>";
- if ($count != 0) {
- echo "<a title=\"$strmoveup\" href=\"".$pageurl->out_action(array('up'=>$count))."\"><img
- src=\"$CFG->pixpath/t/up.gif\" class=\"iconsmall\" alt=\"$strmoveup\" /></a>";
+</div>
+</form>
+
+ </div>
+<?php
+ }else if ($reordertool) {
+ if ($qnum) {
+ ?>
+<div class="qorder">
+ <?php
+ echo '<input type="text" name="o'.$i.'" size="2" value="'.
+ (10*$count+10).
+ '" tabindex="'.($lastindex+$qno).
+ '" '.$movedisabled.' />';
+ ?>
+<!-- <input type="submit" class="pointssubmitbutton" value="<?php
+ echo $strsave; ?>" /> -->
+</div>
+<?php
+ }
+ }
+?>
+ <div class="questioncontentcontainer">
+ <?php
+ //strcmp returns 0 if equal
+ if (strcmp($question->qtype,'random')===0){ // 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, $questionurl, $quiz);
+ }else{
+ quiz_print_singlequestion_reordertool($question,
+ $questionurl, $quiz);
+ }
+ }
+ ?>
+ </div>
+ </div>
+ </div>
+</div>
+
+ <?php
+ /* Display question end */
+ $count++;
+ $sumgrade += $quiz->grades[$qnum];
+
+ }
}
- echo "</td>";
- echo "<td>";
- if ($count < $lastindex-1) {
- echo "<a title=\"$strmovedown\" href=\"".$pageurl->out_action(array('down'=>$count))."\"><img
- src=\"$CFG->pixpath/t/down.gif\" class=\"iconsmall\" alt=\"$strmovedown\" /></a>";
+ //a page break: end the existing page.
+ if($qnum == 0){
+ if($pageopen){
+ if(!$reordertool){
+ 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="o'.$i.'" size="2" value="'.
+ (10*$count+10).'" />';
+ }
+ echo "</div></div>";
+
+ if(!$reordertool){
+ 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>";
+ }
+ $pagecount;
+ $pageopen=false;
+ $count++;
+ }
}
- echo "</td>";
- if (!$quiz->shufflequestions) {
- // Print and increment question number
- echo '<td>'.($question->length ? $qno : ' ').'</td>';
- $qno += $question->length;
+ }
+ if($reordertool){
+ echo $reordercontrolsbottom;
+ echo '</div></form>';
+ }
+
+
+
+ return $sumgrade;
+}
+
+/**
+ * Print all the controls for adding questions directly into the
+ * specific page in the edit tab of edit.php
+ *
+ * @param unknown_type $quiz
+ * @param unknown_type $pageurl
+ * @param unknown_type $page
+ * @param unknown_type $hasattempts
+ */
+function quiz_print_pagecontrols($quiz,$pageurl,$page, $hasattempts){
+ global $CFG;
+ $strcreatenewquestion=get_string("createnewquestion",'quiz');
+ $strselectquestiontype=get_string("selectquestiontype",'quiz');
+ echo '<div class="pagecontrols">';
+ // get the current context
+ $thiscontext = get_context_instance(CONTEXT_COURSE, $quiz->course);
+ $contexts = new question_edit_contexts($thiscontext);
+ // get default category and turn its infor into a string that works in an url
+ $defaultcategory = question_make_default_categories($contexts->all());
+ $categorystring = "$defaultcategory->id,$defaultcategory->contextid";
+ //create the url the question page will return to
+ $returnurl_addtoquiz=new moodle_url($pageurl->out(true),
+ array("addonpage"=>$page));
+ //create the url of the new question page to forward to. return url is given
+ //as a parameter and automatically urlencoded.
+ $newquestionparams = array('returnurl' => $returnurl_addtoquiz->out(false),
+ 'cmid'=>$quiz->cmid, "appendqnumstring"=>"addquestion", "category"=>$categorystring);
+ $newquestionurl_object = new moodle_url("$CFG->wwwroot/question/question.php",
+ $newquestionparams);
+ $newquestionurl=$newquestionurl_object->out(false);
+ echo get_string("addquestion","quiz").": ";
+ if ($hasattempts) {
+ $disabled = 'disabled="disabled"';
+ } else {
+ $disabled = '';
+ }
+ popup_form ($newquestionurl.'&qtype=',
+ question_type_menu(),
+ "addquestion_$page",
+ "",
+ $strselectquestiontype,
+ "",
+ "",
+ false,
+ "self",
+ "",
+ null,
+ $strcreatenewquestion, $hasattempts);
+ helpbutton("questiontypes", $strcreatenewquestion, "quiz");
+ echo '<div class="adddescription">';
+ print_single_button($CFG->wwwroot."/question/question.php",
+ array("cmid"=>$quiz->cmid,
+ "courseid"=>$quiz->course,
+ "returnurl"=>$returnurl_addtoquiz->out(false),
+ "appendqnumstring"=>"addquestion",
+ "category"=>$categorystring,
+ "qtype"=>"description"),
+ get_string("adddescriptionlabel","quiz"),'get', '_self', false, '',
+ $hasattempts);
+ echo "\n</div>";
+ ?>
+ <div class="addrandomquestion">
+ <div class="singlebutton">
+ <form class="randomquestionform" action="<?php echo $CFG->wwwroot; ?>/mod/quiz/addrandom.php" method="get">
+ <div>
+ <input type="hidden" class="addonpage_formelement" name="addonpage_form" value="<?php echo $page; ?>" />
+ <input type="hidden" name="cmid" value="<?php echo $quiz->cmid; ?>" />
+ <input type="hidden" name="courseid" value="<?php echo $quiz->course; ?>" />
+ <input type="hidden" name="returnurl" value="<?php echo urlencode($pageurl->out(true)); ?>" />
+ <input type="submit" id="addrandomdialoglaunch_<?php echo $page; ?>" value="<?php echo get_string("addrandomquestion","quiz"); ?>" <?php echo " $disabled"; ?> />
+ <!--<a href="#" id="addrandomdialoglaunch_<?php echo $page; ?>">laa</a>-->
+ <?php helpbutton('random', get_string('random', 'quiz'), 'quiz', true, false, '');
+ ?>
+ </div>
+ </form>
+ </div>
+ </div>
+ <?php
+ echo "\n</div>";
+}
+/**
+ * Process submitted form data to create a new category for a random question
+ * This is used by edit.php and addrandom.php
+ * cmid
+ *
+ * @param object $qcobject
+ * @param boolean $redirect if true, redirect to edit.php with GET
+ * parameters to add the question
+ * @param integer $cmid id of the quiz' course module; required if $redirect=true
+ * @return mixed category_id if $redirect==false and operation successfull, returns new category's id. if operation failed, returns false.
+ */
+function quiz_process_randomquestion_formdata(&$qcobject, $redirect=false, $cmid=0){
+ global $CFG,$DB;
+ $newrandomcategory=0;
+ $addonpage=0;
+ if ($redirect && !$cmid){
+ return false;
+ }
+ if ($qcobject->catform_rand->is_cancelled()){
+ return false;
+ }elseif ($catformdata = $qcobject->catform_rand->get_data()) {
+ $addonpage=$catformdata->addonpage;
+ if (!$catformdata->id) {//new category
+ $newrandomcategory=$qcobject->add_category($catformdata->parent,
+ $catformdata->name, $catformdata->info,true);
+ if(!is_null($newrandomcategory)){
+ if (! $newcategory = $DB->get_record('question_categories',
+ array('id'=>$newrandomcategory))) {
+ print_error('invalidcategoryid');
+ }
+ }else{
+ print_error("cannotcreatecategory");
+ return false;
+ }
} else {
- echo '<td> </td>';
+ print_error("cannotcreatecategory");
+ return false;
}
+ }
+ if ($redirect && $newrandomcategory){
+ redirect($CFG->wwwroot."/mod/quiz/edit.php?cmid=$cmid&addonpage=$addonpage&addrandom=1&categoryid=$newrandomcategory&randomcount=1&sesskey=".sesskey());
+ }else{
+ return($newrandomcategory);
- 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="' . ($quiz->decimalpoints + 2) . '" value="'.(0 + $quiz->grades[$qnum]).
- '" tabindex="'.($lastindex+$qno).'" />';
+ }
+}
+
+
+/**
+ * Print a simple question list of the questions in a question bank category.
+ * Used for random question display in the edit tab of edit.php
+ */
+function quiz_simple_question_list($pageurl, $categorylist, $numbertoshow=3,
+ $showhidden=false, $sortorderdecoded='qtype, name ASC',
+ $showquestiontext = true){
+ global $DB;
+
+ // hide-feature
+ $showhidden = $showhidden ? '' : " AND hidden = '0'";
+ $categorylist_array = explode(',', $categorylist);
+ list($usql, $params) = $DB->get_in_or_equal($categorylist_array);
+
+ if (!$questions = $DB->get_records_select('question',
+ "category $usql AND parent = '0' $showhidden",
+ $params, $sortorderdecoded, '*', 0, $numbertoshow)) {
+ // There are no questions on the requested page.
+ $page = 0;
+ if (!$questions = $DB->get_records_select('question',
+ "category $usql AND parent = '0' $showhidden",
+ $params, $sortorderdecoded, '*', 0, $numbertoshow)) {
+ // There are no questions at all
+ //TODO: if moodle used PHP exceptions, we would raise one here so that
+ //the main UI would know to display quis status "unfinished".
+ return;
}
- echo '</td><td align="center">';
- echo quiz_question_action_icons($quiz, $quiz->cmid, $question, $pageurl->out());
- 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))."\">
- <img src=\"$CFG->pixpath/t/$movearrow\" class=\"iconsmall\" alt=\"$strremove\" /></a>";
+ }
+ foreach ($questions as $question) {
+ echo "<li>";
+ quiz_question_tostring($question,true, $showquestiontext, false);
+ echo "</li>";
+ }
+}
+/**
+ * Print a given single question in quiz for the edit tab of edit.php.
+ * Meant to be used from quiz_print_question_list()
+ */
+function quiz_print_singlequestion(&$question, &$questionurl, &$quiz){
+ $stredit = get_string("edit");
+ $strview = get_string("view");
+
+ global $COURSE,$QTYPES,$CFG;
+ ?>
+ <div class="singlequestion">
+ <?php
+ $formatoptions = new stdClass;
+ $formatoptions->noclean = false;
+ $formatoptions->para = false;
+ $formatoptions->newlines = false;
+ $questiontext=strip_tags(format_text($question->questiontext,
+ FORMAT_MOODLE,$formatoptions, $COURSE->id));
+ if (question_has_capability_on($question, 'edit', $question->category)
+ || question_has_capability_on($question, 'move',
+ $question->category)) {
+ echo "<a title=\"$stredit\" href=\"".$questionurl->out()."\">".
+ quiz_question_tostring($question,false).
+ '<span class="editicon">'.
+ "<img src=\"$CFG->pixpath/t/edit.gif\" alt=\"".
+ get_string("edit")."\" /></span>".
+ "</a>";
+ }
+ elseif (question_has_capability_on($question, 'view',
+ $question->category)){
+ echo "<a title=\"$strview\" href=\"".
+ $questionurl->out(false, array('id'=>$question->id))."\">".
+ quiz_question_tostring($question,false).
+ '<span class="editicon">'.
+ "<img src=\"$CFG->pixpath/i/info.gif\" ".
+ "alt=\"$strview\" /></span>".
+ "</a>";
+ }else{
+ //TODO: this should be a call to quiz_question_tostring, right?
+ echo $questiontext;
+ }
+ echo '<span class="questiontype">';
+ $namestr = $QTYPES[$question->qtype]->menu_name();
+ print_question_icon($question);
+ echo " $namestr</span>";
+ echo '<span class="questionpreview">'.
+ quiz_question_preview_button($quiz, $question).'</span>';
+ ?>
+ </div><?php
+}
+/**
+ * Print a given random question in quiz for the edit tab of edit.php.
+ * Meant to be used from quiz_print_question_list()
+ */
+function quiz_print_randomquestion(&$question, &$pageurl, &$quiz,$quiz_qbanktool){
+ global $DB;
+ echo '<div class="quiz_randomquestion">';
+
+ //TODO: Tim? I left this out from the below get_record call:, , 'contextid' => $contextid
+ if (!$category = $DB->get_record('question_categories', array('id' => $question->category))) {
+ notify('Random question category not found!');
+ return;
+ }
+
+ echo '<div class="randomquestionfromcategory">';
+ print_question_icon($question);
+ print_string('random','quiz');
+ echo " ".get_string("fromcategory",'quiz').":</div>";
+
+ echo '<div class="randomquestioncategory">';
+ echo '<a href="'.
+ $pageurl->out(false,array("qbanktool"=>1,
+ "cat"=>$category->id.','.$category->contextid)).
+ '">'.$category->name.'</a>';
+ //TODO: URGENT fix question preview for random questions
+ /*echo '<span class="questionpreview">'.
+ quiz_question_preview_button($quiz, $question).
+ '</span>';
+ */
+
+ echo "</div>";
+
+ $questioncount=$DB->count_records_select('question',
+ "category IN ($category->id) AND parent = '0' ");
+
+ echo '<div class="randomquestionqlist">';
+ $randomquestionlistsize=3;
+ if(!$questioncount){
+ echo '<span class="error">';
+ print_string("noquestionsnotinuse", "quiz");
+ echo '<br />';
+ if(!$quiz_qbanktool){
+ echo '<a href="'.
+ $pageurl->out(false,array("qbanktool"=>1,
+ "cat"=>$category->id.','.$category->contextid)).
+ '">';
+ }
+ echo get_string("addnewquestionsqbank","quiz",
+ "<strong>$category->name</strong>");
+ if(!$quiz_qbanktool){
+ echo '</a>';
}
- echo "</td></tr>";
- $count++;
- $sumgrade += $quiz->grades[$qnum];
+ echo '</span>';
+ }else{
+ echo "<ul>";
+ quiz_simple_question_list($pageurl, $question->category,
+ $randomquestionlistsize);
+ echo '<li class="totalquestionsinrandomqcategory">';
+ if ($questioncount>$randomquestionlistsize){
+ echo "... ";
+ }
+ print_string("totalquestionsinrandomqcategory","quiz",$questioncount);
+ echo "</li>";
+ echo "</ul>";
}
- 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 "</div>";
- 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="' . ($quiz->decimalpoints + 2) . '" tabindex="'.($qno+1)
- .'" value="'.quiz_format_grade($quiz, $quiz->grade).'" />';
- echo '</td><td align="left">';
- helpbutton("maxgrade", get_string("maximumgrade"), "quiz");
- echo "</td></tr></table>\n";
+ echo '<div class="randomquestioncategorycount">';
+ echo "</div>";
- echo '<div class="quizquestionlistcontrols"><input type="submit" value="'.get_string('savechanges').'" />';
- echo '<input type="hidden" name="savechanges" value="save" /></div>';
+ echo "</div>";
- echo '</fieldset>';
- echo "</form>\n";
+}
- if (!$quiz->shufflequestions) {
- echo '<div id="showhidepagingcontrols">';
+/**
+ * Print a given single question in quiz for the reordertool tab of edit.php.
+ * Meant to be used from quiz_print_question_list()
+ */
+function quiz_print_singlequestion_reordertool(&$question, &$questionurl, &$quiz){
+ $stredit = get_string("edit");
+ $strview = get_string("view");
- /// Button to show or hide pagebreaks.
- if ($showbreaks) {
- $newshowbreaks = 0;
- $caption = get_string('hidebreaks', 'quiz');
- } else {
- $newshowbreaks = 1;
- $caption = get_string('showbreaks', 'quiz');
+ global $COURSE,$QTYPES, $CFG;
+ $reordercheckboxlabel='<label for="s'.$question->id.'">';
+ $reordercheckboxlabelclose='</label>';
+
+ ?>
+ <div class="singlequestion">
+ <?php
+ $formatoptions = new stdClass;
+ $formatoptions->noclean = false;
+ $formatoptions->para = false;
+ $formatoptions->newlines = false;
+ echo $reordercheckboxlabel;
+ print_question_icon($question);
+ echo "$reordercheckboxlabelclose ";
+ $questiontext=strip_tags(format_text($question->questiontext,
+ FORMAT_MOODLE,$formatoptions, $COURSE->id));
+ $editstring="";
+ if (question_has_capability_on($question, 'edit', $question->category) || question_has_capability_on($question, 'move', $question->category)) {
+ echo "$reordercheckboxlabel ".
+ quiz_question_tostring($question,false).
+ $reordercheckboxlabelclose;
+ $editstring="<a title=\"$stredit\" href=\"".
+ $questionurl->out(false, array('id'=>$question->id)).
+ "\"><img src=\"$CFG->pixpath/t/edit.gif\" alt=\"".
+ $stredit."\" /> </a>";
+ } elseif (question_has_capability_on($question, 'view',
+ $question->category)){
+ echo "$reordercheckboxlabel".
+ quiz_question_tostring($question,false).
+ "$reordercheckboxlabelclose";
+ $editstring="<a title=\"$strview\" href=\"".$questionurl->out(false,
+ array('id'=>$question->id))."\">$questionstring <img
+ src=\"$CFG->pixpath/i/info.gif\" alt=\"$strview\" /></a>";
+ }else{
+ echo "$reordercheckboxlabel".
+ quiz_question_tostring($question,false).
+ "$reordercheckboxlabelclose";
+ }
+ echo '<span class="questionpreview">'.$editstring.
+ quiz_question_preview_button($quiz, $question, false).
+ '</span>';
+ ?>
+ </div><?php
+}
+/**
+ * Print a given random question in quiz for the reordertool tab of edit.php.
+ * Meant to be used from quiz_print_question_list()
+ */
+
+function quiz_print_randomquestion_reordertool(&$question, &$pageurl, &$quiz){
+ global $CFG,$DB;
+ $stredit = get_string("edit");
+ $strview = get_string("view");
+
+ echo '<div class="quiz_randomquestion">';
+
+ //TODO: Tim? I left this out from the below get_record call:, 'contextid', $contextid
+ if (!$category = $DB->get_record('question_categories', array('id' => $question->category))) {
+ notify('Random question category not found!');
+ return;
+ }
+ echo '<div class="randomquestionfromcategory">';
+ $url=$pageurl->out(false,array("qbanktool"=>1, "cat"=>$category->id.','.
+ $category->contextid));
+ $reordercheckboxlabel='<label for="s'.$question->id.'">';
+ $reordercheckboxlabelclose='</label>';
+
+ echo $reordercheckboxlabel;
+ print_question_icon($question);
+ $editstring= "<a title=\"$stredit\" href=\"".$url.
+ "\"><img src=\"$CFG->pixpath/t/edit.gif\" alt=\"".
+ get_string("edit")."\" /> </a>";
+ $questioncount=$DB->count_records_select('question',
+ "category IN ($category->id) AND parent = '0' ");
+ $randomquestionlistsize=3;
+
+ if(!$questioncount){
+ echo '<span class="error">';
+ print_string("empty", "quiz");
+ echo '</span> ';
+ }
+
+ print_string('random','quiz');
+ echo ": $reordercheckboxlabelclose</div>";
+
+ echo '<div class="randomquestioncategory">';
+ echo '<!--<a href="'.
+ $pageurl->out(false,array("qbanktool"=>1, "cat"=>$category->id.','.
+ $category->contextid)).
+ '">-->'.$reordercheckboxlabel.$category->name.
+ $reordercheckboxlabelclose.'<!--</a>-->';
+ echo '<span class="questionpreview">'.$editstring;
+ //TODO: URGENT fix question preview for random questions
+ /*echo
+ quiz_question_preview_button($quiz, $question);
+ */
+ echo '</span>';
+ echo "</div>";
+
+
+ echo '<div class="randomquestioncategorycount">';
+ echo "</div>";
+
+ echo "</div>";
+
+}
+/**
+ * Creates a textual representation of a question for display.
+ */
+function quiz_question_tostring(&$question,$showicon=false,$showquestiontext=true, $return=true){
+ global $COURSE;
+ $result="";
+ $result.='<span class="questionname">';
+ if($showicon){
+ $result.=print_question_icon($question,true);
+ echo " ";
}
- print_single_button($pageurl->out(true),
- array('showbreaks' => $newshowbreaks) + $pageurl->params(), $caption);
+ $result.=shorten_text(format_string($question->name),200).'</span>';
+ if($showquestiontext){
+ $formatoptions = new stdClass;
+ $formatoptions->noclean = true;
+ $formatoptions->para = false;
+ $questiontext=strip_tags(format_text($question->questiontext,
+ $question->questiontextformat,
+ $formatoptions, $COURSE->id));
+ $questiontext=shorten_text($questiontext,200);
+ $result.='<span class="questiontext">';
+ if(!empty($questiontext)){
+ $result.=$questiontext;
+ }else{
+ //TODO: if moodle used PHP exceptions, we would raise one here so that
+ //the main UI would know to display quis status "unfinished".
+ $result.='<span class="error">';
+ $result.= get_string("questiontextisempty","quiz");
+ $result.='</span>';
+ }
+ $result.='</span>';
+ }
+ if($return){
+ return $result;
+ }else{
+ echo $result;
+ }
+}
- echo ' ';
- /// Button to show or hide the reordering tool.
- if ($reordertool) {
- $newreordertool = 0;
- $caption = get_string('hidereordertool', 'quiz');
- } else {
- $newreordertool = 1;
- $caption = get_string('reordertool', 'quiz');
+
+
+
+/**
+ * Shows the question bank editing interface.
+ * A changed copy of the function at question/editlib.php; to be refactored.
+ *
+ * The function also processes a number of actions:
+ *
+ * Actions affecting the question pool:
+ * move Moves a question to a different category
+ * deleteselected Deletes the selected questions from the category
+ * Other actions:
+ * category Chooses the category
+ * displayoptions Sets display options
+ *
+ * @author Martin Dougiamas and many others. This has recently been extensively
+ * rewritten by Gustav Delius and other members of the Serving Mathematics project
+ * {@link http://maths.york.ac.uk/serving_maths}
+ * @param moodle_url $pageurl object representing this pages url.
+ */
+function quiz_question_showbank($tabname, $contexts, $pageurl, $cm,
+ $page, $perpage, $sortorder, $sortorderdecoded, $cat, $recurse,
+ $showhidden, $showquestiontext, $cmoptions){
+ global $COURSE,$DB;
+
+ if (optional_param('deleteselected', false, PARAM_BOOL)){ // teacher still has to confirm
+ // make a list of all the questions that are selected
+ $rawquestions = $_REQUEST; // This code is called by both POST forms and GET links, so cannot use data_submitted.
+ $questionlist = ''; // comma separated list of ids of questions to be deleted
+ $questionnames = ''; // string with names of questions separated by <br /> with
+ // an asterix in front of those that are in use
+ $inuse = false; // set to true if at least one of the questions is in use
+ foreach ($rawquestions as $key => $value) { // Parse input for question ids
+ if (preg_match('!^q([0-9]+)$!', $key, $matches)) {
+ $key = $matches[1];
+ $questionlist .= $key.',';
+ question_require_capability_on($key, 'edit');
+ if (record_exists('quiz_question_instances', 'question', $key)) {
+ $questionnames .= '* ';
+ $inuse = true;
+ }
+ $questionnames .= get_field('question', 'name', 'id', $key).
+ '<br />';
+ }
+ }
+ if (!$questionlist) { // no questions were selected
+ redirect($pageurl->out());
}
- print_single_button($pageurl->out(true),
- array('reordertool' => $newreordertool) + $pageurl->params(), $caption);
- helpbutton('reorderingtool', get_string('reordertool', 'quiz'), 'quiz');
+ $questionlist = rtrim($questionlist, ',');
- echo '</div>';
+ // Add an explanation about questions in use
+ if ($inuse) {
+ $questionnames .= '<br />'.get_string('questionsinuse', 'quiz');
+ }
+ notice_yesno(get_string("deletequestionscheck", "quiz", $questionnames),
+ $pageurl->out_action(array('deleteselected'=>$questionlist,
+ 'confirm'=>md5($questionlist))),
+ $pageurl->out_action());
+ }else{
+ //actual question bank
+ // starts with category selection form
+ list($categoryid, $contextid)= explode(',', $cat);
- /// Repaginate form.
- echo '<form method="post" action="edit.php" id="showbreaks">';
- echo '<div>';
- echo $pageurl->hidden_params_out();
- echo '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />';
- $perpage= array();
- $perpage[0] = get_string('allinone', 'quiz');
- for ($i=1; $i<=50; ++$i) {
- $perpage[$i] = $i;
- }
- print_string('repaginate', 'quiz', choose_from_menu($perpage, 'questionsperpage',
- $quiz->questionsperpage, '', '', '', true));
- echo ' <input type="submit" name="repaginate" value="'. get_string('go') .'" />';
- echo '</div>';
- echo '</form>';
+ if (!$categoryid) {
+ print_box_start('generalbox questionbank');
+ quiz_question_category_form($contexts->having_one_edit_tab_cap($tabname), $pageurl, $cat, $recurse, $showhidden, $showquestiontext);
+ echo "<p style=\"text-align:center;\"><b>";
+ print_string("selectcategoryabove", "quiz");
+ echo "</b></p>";
+ print_box_end();
+ return;
+ }
+
+ if (!$category = $DB->get_record('question_categories',
+ array('id' => $categoryid, 'contextid' => $contextid))) {
+ print_box_start('generalbox questionbank');
+ notify('Category not found!');
+ print_box_end();
+ return;
+ }
+ $formatoptions = new stdClass;
+ $formatoptions->noclean = true;
+ $strcategory = get_string('category', 'quiz');
+ echo '<div class="categoryinfo"><div class="categorynamefieldcontainer">'.
+ $strcategory;
+ echo ': <span class="categorynamefield">';
+ echo shorten_text(strip_tags(format_text($category->name, FORMAT_MOODLE,
+ $formatoptions, $COURSE->id)),60);
+ echo '</span></div><div class="categoryinfofieldcontainer"><span class="categoryinfofield">';
+ echo shorten_text(strip_tags(format_text($category->info, FORMAT_MOODLE,
+ $formatoptions, $COURSE->id)),200);
+ echo '</span></div></div>';
+
+ print_box_start('generalbox questionbank');
+
+ quiz_question_category_form($contexts->having_one_edit_tab_cap($tabname),
+ $pageurl, $cat, $recurse, $showhidden, $showquestiontext);
+ // continues with list of questions
+
+ quiz_question_list($contexts->having_one_edit_tab_cap($tabname),
+ $pageurl,
+ $cat,
+ isset($cm) ? $cm : null,
+ $recurse,
+ $page,
+ $perpage,
+ $showhidden,
+ $sortorder,
+ $sortorderdecoded,
+ $showquestiontext,
+ $contexts->having_cap('moodle/question:add'),
+ $cmoptions);
+
+ echo '<hr/><form method="get" action="edit.php" id="displayoptions">';
+ echo "<fieldset class='invisiblefieldset'>";
+ echo $pageurl->hidden_params_out(array('recurse', 'showhidden',
+ 'showquestiontext'));
+ question_category_form_checkbox('recurse', $recurse);
+ question_category_form_checkbox('showhidden', $showhidden);
+ echo '<noscript><div class="centerpara"><input type="submit" value="'.
+ get_string('go') .'" />';
+ echo '</div></noscript></fieldset></form>';
+
+ print_box_end();
}
- return $sumgrade;
}
+/**
+ * prints a form to choose categories
+ * A changed copy of the function at question/editlib.php; to be refactored.
+ *
+ */
+function quiz_question_category_form($contexts, $pageurl, $current, $recurse=1,
+ $showhidden=false, $showquestiontext=false) {
+ global $CFG;
-?>
+/// Get all the existing categories now
+ $catmenu = question_category_options($contexts, false, 0, true);
+
+ $strcategory = get_string('category', 'quiz');
+ $strselectcategory = get_string('selectcategory', 'quiz');
+ $strshow = get_string('show', 'quiz');
+ $streditcats = get_string('editcategories', 'quiz');
+
+ popup_form ('edit.php?'.$pageurl->get_query_string().'&category=',
+ $catmenu, 'catmenu', $current, '', '', '', false, 'self',
+ $strselectcategory.":");
+}
+
+
+
+/**
+* Prints the table of questions in a category with interactions
+* A changed copy of the function at question/editlib.php; to be refactored.
+*
+* @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 quiz_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(), $cmoptions) {
+ global $USER, $CFG, $THEME, $COURSE, $DB;
+ 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 = $DB->get_record('question_categories',
+ array('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;
+ }
+ //create the url of the new question page to forward to. return url is given
+ //as a parameter and automatically urlencoded.
+
+
+
+ $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);
+ }
+
+
+ $categorylist = ($recurse) ? question_categorylist($category->id) : $category->id;
+
+ // hide-feature
+ $showhidden = $showhidden ? '' : " AND hidden = '0'";
+ echo '<div class="createnewquestion">';
+ if ($canadd) {
+ popup_form ($questionurl->out(false, array('category' => $category->id)).
+ '&qtype=', $qtypemenu, "addquestion_$page", "", "choose", "",
+ "", false, "self", "<strong>$strcreatenewquestion</strong>");
+ helpbutton("questiontypes", $strcreatenewquestion, "quiz");
+ }
+ else {
+ print_string('nopermissionadd', 'question');
+ }
+ echo '</div>';
+
+
+ $categorylist_array = explode(',', $categorylist);
+
+ list($usql, $params) = $DB->get_in_or_equal($categorylist_array);
+ if (!$totalnumber = $DB->count_records_select('question',
+ "category $usql AND parent = '0' $showhidden", $params)) {
+ echo '<div class="categoryquestionscontainer noquestionsincategory">';
+ print_string("noquestions", "quiz");
+ echo "</div>";
+ return;
+ }
+
+ if (!$questions = $DB->get_records_select('question',
+ "category $usql AND parent = '0' $showhidden", $params, $sortorderdecoded,
+ '*', $page*$perpage, $perpage)) {
+
+ // There are no questions on the requested page.
+ $page = 0;
+ if (!$questionsatall = $DB->get_records_select('question',
+ "category $usql AND parent = '0' $showhidden", $params, $sortorderdecoded,
+ '*', 0, $perpage)) {
+ // There are no questions at all
+ echo '<div class="categoryquestionscontainer noquestionsincategory">';
+ print_string("noquestions", "quiz");
+ echo "</div>";
+ return;
+ }
+ }
+
+
+
+ echo '<div class="categorysortopotionscontainer">';
+ echo question_sort_options($pageurl, $sortorder);
+ echo '</div>';
+ echo '<div class="categorypagingbarcontainer">';
+ print_paging_bar($totalnumber, $page, $perpage, $pageurl, 'qpage');
+ echo '</div>';
+
+ 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 '<div class="categoryquestionscontainer">';
+ echo '<table id="categoryquestions" style="width: 100%"><colgroup><col id="qaction"></col><col id="qname"></col><col id="qextraactions"></col></colgroup><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>";
+ echo "<th style=\"white-space:nowrap; text-align: left;\" class=\"header\" scope=\"col\"></th>";
+ echo "</tr>\n";
+ foreach ($questions as $question) {
+ $nameclass = '';
+ $textclass = '';
+ if ($question->hidden) {
+ $nameclass = 'dimmed_text';
+ $textclass = 'dimmed_text';
+ }
+ if ($showquestiontext) {
+ $nameclass .= ' header';
+ }
+ 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,$cmoptions);
+ }
+
+ if ($caneditall || $canmoveall || $canuseall){
+ echo "<input title=\"$strselect\" type=\"checkbox\" name=\"q$question->id\" id=\"checkq$question->id\" value=\"1\" />";
+ }
+ echo "</td>\n";
+
+ echo "<td $nameclass><div>";
+ $questionstring=quiz_question_tostring($question,false,true,true);
+ echo "<label for=\"checkq$question->id\">";
+ print_question_icon($question);
+ echo " $questionstring</label>";
+
+
+
+ echo "</div></td>\n";
+ echo "<td>";
+ // 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
+ 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
+ src=\"$CFG->pixpath/i/info.gif\" alt=\"$strview\" /></a>";
+ }
+ // 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);
+ }
+ echo "</td>";
+
+ 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></div>\n";
+
+
+
+
+ echo '<div class="categorypagingbarcontainer pagingbottom">';
+ $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;
+ echo '</div>';
+ echo '<div class="categoryselectallcontainer">';
+ 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 "</div>\n";
+ echo '<div class="modulespecificbuttonscontainer">';
+ if ($caneditall || $canmoveall || $canuseall){
+ echo '<strong> '.get_string('withselected', 'quiz').':</strong><br />';
+ if (function_exists('module_specific_buttons')) {
+ echo module_specific_buttons($cm->id,$cmoptions);
+ }
+ // print delete and move selected question
+ if ($caneditall) {
+ echo '<input type="submit" name="deleteselected" value="'.
+ $strdelete."\" />\n";
+ }
+ if (function_exists('module_specific_controls') && $canuseall) {
+ $modulespecific=module_specific_controls($totalnumber, $recurse, $category,
+ $cm->id,$cmoptions);
+ if(!empty($modulespecific)){
+ echo "<hr />$modulespecific";
+ }
+ }
+ }
+ echo "</div>\n";
+
+ echo '</fieldset>';
+ echo "</form>\n";
+}
+
+?>
\ No newline at end of file
$attempt->userid = $USER->id;
$attempt->preview = 0;
if ($quiz->shufflequestions) {
- $attempt->layout = quiz_repaginate($quiz->questions, $quiz->questionsperpage, true);
+ $attempt->layout = quiz_clean_layout(quiz_repaginate($quiz->questions, $quiz->questionsperpage, true),true);
} else {
- $attempt->layout = $quiz->questions;
+ $attempt->layout = quiz_clean_layout($quiz->questions,true);
}
} else {
/// Build on last attempt.
* So 5,2,0,3,0 means questions 5 and 2 on page 1 and question 3 on page 2
*/
function quiz_questions_in_quiz($layout) {
- return str_replace(',0', '', $layout);
+ if($layout){
+ $layout=str_replace(',0', '', $layout);
+ //remove also the zero in the beginning, if any
+ if(isset($layout[0]) && $layout[0]=="0" &&
+ isset($layout[1]) && $layout[1]==","){
+ $layout=substr($layout,2);
+ }
+ }
+ return $layout;
}
/**
* @param string $layout The string representing the quiz layout.
*/
function quiz_number_of_pages($layout) {
- return substr_count($layout, ',0');
+ $count=0;
+ if($layout){
+ //if the first page is empty, include it, too
+ if (strcmp($layout[0],"0")===0){
+ $count++;
+ }
+ $count+=substr_count($layout, ',0');
+ }
+ return $count;
+}
+/**
+ * Returns the number of questions in the quiz layout
+ *
+ * @return integer Comma separated list of question ids
+ * @param string $layout The string representing the quiz layout.
+ */
+function quiz_number_of_questions_in_quiz($layout) {
+ //TODO: clean layout before counting
+ //TODO: remove page breaks
+ $layout=quiz_questions_in_quiz($layout);
+ $count=substr_count($layout, ',');
+ if($count>0){
+ $count++;
+ }
+ return $count;
}
/**
function quiz_repaginate($layout, $perpage, $shuffle=false) {
$layout = str_replace(',0', '', $layout); // remove existing page breaks
$questions = explode(',', $layout);
+ //remove empty pages from beginning
+ while (reset($questions) == '0') {
+ array_shift($questions);
+ }
if ($shuffle) {
srand((float)microtime() * 1000000); // for php < 4.2
shuffle($questions);
$stredit = get_string('edit');
$strview = get_string('view');
}
- $html ='';
+ $html ='';
if (($question->qtype != 'random')){
$html .= quiz_question_preview_button($quiz, $question);
}
* @param object $question the question
* @return the HTML for a preview question icon.
*/
-function quiz_question_preview_button($quiz, $question) {
+function quiz_question_preview_button($quiz, $question, $label=true) {
global $CFG, $COURSE;
if (!question_has_capability_on($question, 'use', $question->category)){
return '';
}
$strpreview = get_string('previewquestion', 'quiz');
+ $strpreviewlabel="";
+ if($label){
+ $strpreviewlabel = " ".get_string('preview', '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\" />",
+ "<img src=\"$CFG->pixpath/t/preview.gif\" class=\"iconsmall\" alt=\"$strpreview\" />$strpreviewlabel",
0, 0, $strpreview, QUESTION_PREVIEW_POPUP_OPTIONS, true);
}
// return the number of successfully sent emails
return $emailresult['good'];
}
+function print_timing_information($quiz,$showopenstatus=false){
+ $timenow = time();
+ $available = ($quiz->timeopen < $timenow and ($timenow < $quiz->timeclose or !$quiz->timeclose));
+ if ($available) {
+ if ($quiz->timelimit) {
+ echo get_string("quiztimelimit","quiz", format_time($quiz->timelimit * 60))."</p>";
+ }
+ if ($quiz->timeopen) {
+ echo get_string('quizopens', 'quiz'), ': ', userdate($quiz->timeopen);
+ }
+ if ($quiz->timeclose) {
+ echo get_string('quizcloses', 'quiz'), ': ', userdate($quiz->timeclose);
+ }
+ if($showopenstatus){
+ if(!$quiz->timelimit && !$quiz->timeopen && !$quiz->timeclose){
+ echo get_string('quizopened', 'quiz');
+ }
+ }
+ } else if ($timenow < $quiz->timeopen) {
+ echo get_string("quiznotavailable", "quiz", userdate($quiz->timeopen));
+ } else {
+ echo get_string("quizclosed", "quiz", userdate($quiz->timeclose));
+ }
+ return $available;
+
+}
+function quiz_clean_layout($layout,$removeemptypages=false){
+ //remove duplicate "," (or triple, or...)
+ while(strstr($layout,",,")){
+ $layout = str_replace(',,', ',', $layout);
+ }
+ //remove duplicate question ids
+ $layout_arr=explode(",",$layout);
+ $new_arr=array();
+ $seen=array();
+ //remove duplicate questions
+ foreach($layout_arr as $key=>$value){
+ if(!in_array($value,$seen) && $value!=0){
+ $new_arr[]=$value;
+ $seen[]=$value;
+ }else if($value==0){
+ $new_arr[]=0;
+ }
+ }
+ if($removeemptypages){
+ // Avoid duplicate page breaks
+ // Go through all the array keys
+ for($i=0;$i<count($new_arr);$i++){
+ //check if the current position and the one after are both zeros
+ //remove the one after until they are not both zeros
+ while(isset($new_arr[$i+1]) &&
+ $new_arr[$i]==0 &&
+ $new_arr[$i+1]==0){
+ print_r($new_arr);
+ array_splice($new_arr,$i+1,1);
+ }
+ }
+ }
+ $layout=implode(",",$new_arr);
+ //remove extra "," from beginning and end
+ $layout=trim($layout, ",");
+ //add a ",0" (page break) at the end if there is none
+ $layoutlength=strlen($layout);
+ $last=(strlen($layout)-1);
+ if($layoutlength>1 AND
+ !($layout[$last-1] == ',' AND $layout[$last] == '0')){
+ $layout .= ',0';
+ }
+
+ return $layout;
+}
/**
* Print a quiz error message. This is a thin wrapper around print_error, for convinience.
*
$row = array();
$inactive = array();
$activated = array();
-
+$stredit=get_string('edit');
if (has_capability('mod/quiz:view', $context)) {
$row[] = new tabobject('info', "$CFG->wwwroot/mod/quiz/view.php?id=$cm->id", get_string('info', 'quiz'));
}
$row[] = new tabobject('reports', "$CFG->wwwroot/mod/quiz/report.php?q=$quiz->id", get_string('results', 'quiz'));
}
if (has_capability('mod/quiz:preview', $context)) {
- $row[] = new tabobject('preview', "$CFG->wwwroot/mod/quiz/startattempt.php?cmid=$cm->id&sesskey=" . sesskey(), get_string('preview', 'quiz'));
+ $strpreview = get_string('preview', 'quiz');
+ $row[] = new tabobject('preview', "$CFG->wwwroot/mod/quiz/startattempt.php?cmid=$cm->id&sesskey=" . sesskey(), "<img src=\"$CFG->pixpath/t/preview.gif\" class=\"iconsmall\" alt=\"$strpreview\" /> $strpreview", $strpreview);
}
if (has_capability('mod/quiz:manage', $context)) {
- $row[] = new tabobject('edit', "$CFG->wwwroot/mod/quiz/edit.php?cmid=$cm->id", get_string('edit'));
+ $row[] = new tabobject('edit', "$CFG->wwwroot/mod/quiz/edit.php?cmid=$cm->id", "<img src=\"$CFG->pixpath/t/edit.gif\" class=\"iconsmall\" alt=\"$stredit\" /> $stredit",$stredit);
}
if ($currenttab == 'info' && count($row) == 1) {
$streditingquiz = get_string("editinga", "moodle", $strquiz);
if (has_capability('mod/quiz:manage', $context) && $contexts->have_one_edit_tab_cap('editq')) {
- $row[] = new tabobject('editq', "$CFG->wwwroot/mod/quiz/edit.php?".$thispageurl->get_query_string(), $strquiz, $streditingquiz);
+ //TODO: ensure that removing get_query_string here won't hurt
+ $row[] = new tabobject('editq', "$CFG->wwwroot/mod/quiz/edit.php?cmid=$cm->id", $stredit, $streditingquiz);
+ $row[] = new tabobject('reorder', "$CFG->wwwroot/mod/quiz/edit.php?reordertool=1&cmid=$cm->id", get_string('orderandpaging','quiz'), $streditingquiz);
}
- questionbank_navigation_tabs($row, $contexts, $thispageurl->get_query_string());
+ //questionbank_navigation_tabs($row, $contexts, $thispageurl->get_query_string());
$tabs[] = $row;
}
require_once("$CFG->libdir/listlib.php");
require_once("$CFG->dirroot/question/category_form.php");
+require_once("$CFG->dirroot/question/category_form_randomquestion.php");
require_once('move_form.php');
class question_category_list extends moodle_list {
* @var question_category_edit_form Object representing form for adding / editing categories.
*/
var $catform;
+ /**
+ * @var question_category_edit_form_randomquestion Object representing simplified form for adding a category in order to add it into a quiz as a random question.
+ */
+ var $catform_rand;
/**
* Constructor
list($paged, $count) = $this->editlists[$key]->list_from_records($paged, $count);
}
$this->catform = new question_category_edit_form($this->pageurl, compact('contexts', 'currentcat'));
+ $this->catform_rand = new question_category_edit_form_randomquestion($this->pageurl, compact('contexts', 'currentcat'));
if (!$currentcat){
$this->catform->set_data(array('parent'=>$defaultcategory));
+ $this->catform_rand->set_data(array('parent'=>$defaultcategory));
}
}
/**
$this->output_new_table();
echo '<br />';
+ }
+ /**
+ * Displays the user interface
+ *
+ */
+ function display_randomquestion_user_interface() {
+
+ /// Interface for adding a new category:
+ $this->output_new_randomquestion_table();
+
}
/**
$this->catform->display();
}
+ /**
+ * Outputs a table to allow entry of a new category
+ */
+ function output_new_randomquestion_table() {
+ $this->catform_rand->display();
+ }
+
/**
* Outputs a list to allow editing/rearranging of existing categories
$category->categoryheader = $this->str->edit;
$this->catform->set_data($category);
$this->catform->display();
+ $this->catform_rand->set_data($category);
+ $this->catform_rand->display();
} else {
print_error('invalidcategory', '', '', $categoryid);
}
/**
* Creates a new category with given params
*/
- public function add_category($newparent, $newcategory, $newinfo) {
+ public function add_category($newparent, $newcategory, $newinfo, $return=false) {
global $DB;
if (empty($newcategory)) {
print_error('categorynamecantbeblank', 'quiz');
$cat->info = $newinfo;
$cat->sortorder = 999;
$cat->stamp = make_unique_id_code();
- if (!$DB->insert_record("question_categories", $cat)) {
+ if (!$categoryid=$DB->insert_record("question_categories", $cat)) {
print_error('cannotinsertquestioncate', 'question', '', $newcategory);
} else {
- redirect($this->pageurl->out());//always redirect after successful action
+ if($return){
+ return $categoryid;
+ }else{
+ redirect($this->pageurl->out());//always redirect after successful action
+ }
}
}
--- /dev/null
+<?php //$Id$
+
+require_once($CFG->libdir.'/formslib.php');
+
+class question_category_edit_form_randomquestion extends moodleform {
+
+ function definition() {
+ global $CFG, $DB;
+ $mform =& $this->_form;
+
+ $contexts = $this->_customdata['contexts'];
+ $currentcat = $this->_customdata['currentcat'];
+//--------------------------------------------------------------------------------
+ $mform->addElement('header', 'categoryheader', get_string('createcategoryfornewrandomquestion', 'quiz'));
+
+ $questioncategoryel = $mform->addElement('questioncategory', 'parent', get_string('parentcategory', 'quiz'),
+ array('contexts'=>$contexts, 'top'=>true, 'currentcat'=>$currentcat, 'nochildrenof'=>$currentcat));
+ $mform->setType('parent', PARAM_SEQUENCE);
+ if (1 == $DB->count_records_sql("SELECT count(*)
+ FROM {question_categories} c1,
+ {question_categories} c2
+ WHERE c2.id = ?
+ AND c1.contextid = c2.contextid", array($currentcat))){
+ //TODO: Tim? why does the above evaluate true, breaking the form?
+ // and more importantly, if this is a valid situation, how should we react,
+ // that is, what does this mean?
+ //$mform->hardFreeze('parent');
+ }
+ $mform->setHelpButton('parent', array('categoryparent', get_string('parent', 'quiz'), 'question'));
+
+ $mform->addElement('text','name', get_string('name'),'maxlength="254" size="50"');
+ $mform->setDefault('name', '');
+ $mform->addRule('name', get_string('categorynamecantbeblank', 'quiz'), 'required', null, 'client');
+ $mform->setType('name', PARAM_MULTILANG);
+
+ $mform->addElement('hidden', 'info', '');
+ $mform->setType('info', PARAM_MULTILANG);
+
+//--------------------------------------------------------------------------------
+ $this->add_action_buttons(false, get_string('addrandomquestion', 'quiz'));
+//--------------------------------------------------------------------------------
+ $mform->addElement('hidden', 'id', 0);
+ $mform->setType('id', PARAM_INT);
+ //TODO: Tim: is this questionable? to add a hidden field right from a get parameter?
+ $mform->addElement('hidden', 'addonpage', optional_param("addonpage_form", 0, PARAM_SEQUENCE), 'id="rform_qpage"');
+ $mform->setType('addonpage', PARAM_SEQUENCE);
+ }
+}
+?>
$straddquestions = get_string("addquestions", "quiz");
$strimportquestions = get_string("importquestions", "quiz");
$strexportquestions = get_string("exportquestions", "quiz");
- $strnoquestions = get_string("noquestions", "quiz");
+ $strnoquestions = get_string("noquestionsincategory", "quiz");
$strselect = get_string("select", "quiz");
$strselectall = get_string("selectall", "quiz");
$strselectnone = get_string("selectnone", "quiz");
list($usql, $params) = $DB->get_in_or_equal($categorylist_array);
if (!$totalnumber = $DB->count_records_select('question', "category $usql AND parent = '0' $showhidden", $params)) {
echo "<p style=\"text-align:center;\">";
- print_string("noquestions", "quiz");
+ echo $strnoquestions;
echo "</p>";
return;
}
if (!$questions = $DB->get_records_select('question', "category $usql AND parent = '0' $showhidden", $params, $sortorderdecoded, '*', 0, $perpage)) {
// There are no questions at all
echo "<p style=\"text-align:center;\">";
- print_string("noquestions", "quiz");
+ echo $strnoquestions;
echo "</p>";
return;
}
}
print_paging_bar($totalnumber, $page, $perpage, $pageurl, 'qpage');
-
echo question_sort_options($pageurl, $sortorder);
function question_sort_options($pageurl, $sortorder){
global $USER;
//sort options
- $html = "<div class=\"mdl-align\">";
- $html .= '<form method="post" action="edit.php">';
+ $html = "<div class=\"mdl-align questionsortoptions\">";
+ // POST method should only be used for parameters that change data
+ // or if POST method has to be used, the user must be redirected immediately to
+ // non-POSTed page to not break the back button
+ $html .= '<form method="get" action="edit.php">';
$html .= '<fieldset class="invisiblefieldset" style="display: block;">';
$html .= '<input type="hidden" name="sesskey" value="'.$USER->sesskey.'" />';
$html .= $pageurl->hidden_params_out(array('qsortorder'));
- $sortoptions = array('alpha' => get_string("sortalpha", "quiz"),
- 'typealpha' => get_string("sorttypealpha", "quiz"),
- 'age' => get_string("sortage", "quiz"));
- $html .= choose_from_menu ($sortoptions, 'qsortorder', $sortorder, false, 'this.form.submit();', '0', true);
+ //choose_from_menu concatenates the form name with
+ //"menu" so the label is for menuqsortorder
+ $sortoptions = array('alpha' => get_string("qname", "quiz"),
+ 'typealpha' => get_string("qtypename", "quiz"),
+ 'age' => get_string("age", "quiz"));
+ $a = choose_from_menu ($sortoptions, 'qsortorder', $sortorder, false, 'this.form.submit();', '0', true);
+ $html .= '<label for="menuqsortorder">'.get_string('sortquestionsbyx', 'quiz', $a).'</label>';
$html .= '<noscript><div><input type="submit" value="'.get_string("sortsubmit", "quiz").'" /></div></noscript>';
$html .= '</fieldset>';
$html .= "</form>\n";
$movecontext = optional_param('movecontext', 0, PARAM_BOOL);//switch to make question
//uneditable - form is displayed to edit category only
$returnurl = optional_param('returnurl', 0, PARAM_LOCALURL);
+$appendqnumstring = optional_param('appendqnumstring', '', PARAM_ALPHA);
$inpopup = optional_param('inpopup', 0, PARAM_BOOL);
if ($formeditable && $id){
$toform->categorymoveto = $toform->category;
}
+
+$toform->appendqnumstring = $appendqnumstring;
$toform->returnurl = $returnurl;
$toform->movecontext = $movecontext;
if ($cm !== null){
notify(get_string('changessaved'), '');
close_window(3);
} else {
+ if($appendqnumstring){
+ $returnurl_object=new moodle_url($returnurl);
+ $returnurl=$returnurl_object->out(false,array($appendqnumstring=>($question->id), "sesskey"=>sesskey(), "cmid"=>$cmid));
+ }
redirect($returnurl);
}
} else {
- $nexturlparams = array('returnurl'=>$returnurl);
+ $nexturlparams = array('returnurl'=>$returnurl, 'appendqnumstring'=>$appendqnumstring);
if (isset($fromform->nextpageparam) && is_array($fromform->nextpageparam)){
$nexturlparams += $fromform->nextpageparam;//useful for passing data to the next page which is not saved in the database
}
$mform->setType('returnurl', PARAM_LOCALURL);
$mform->setDefault('returnurl', 0);
+ $mform->addElement('hidden', 'appendqnumstring');
+ $mform->setType('appendqnumstring', PARAM_ALPHA);
+ $mform->setDefault('appendqnumstring', 0);
+
$buttonarray = array();
if (!empty($this->question->id)){
//editing / moving question
$mform->hardFreezeAllVisibleExcept(array('categorymoveto', 'buttonar', 'currentgrp'));
}
}
-
+
function validation($fromform, $files) {
$errors= parent::validation($fromform, $files);
- if (empty($fromform->makecopy) && isset($this->question->id)
- && ($this->question->formoptions->canedit || $this->question->formoptions->cansaveasnew)
+ if (empty($fromform->makecopy) && isset($this->question->id)
+ && ($this->question->formoptions->canedit || $this->question->formoptions->cansaveasnew)
&& empty($fromform->usecurrentcat) && !$this->question->formoptions->canmove){
$errors['currentgrp'] = get_string('nopermissionmove', 'question');
}
return $errors;
}
-
/**
* Add any question-type specific form fields.
#mod-quiz-report .negcovar{
border :medium solid pink;
}
+
+#mod-quiz-edit .questionbankwindow div.header{
+/*this color might need to be theme-specific,
+but in terms of usability, as testing showed,
+//TODO: add url
+it must be ensured that the question
+bank window's title is prominent enough*/
+ background-color:#009;
+ color:#fff;
+ background-image:none;
+}
+
+#mod-quiz-edit div.question div.content div.points,
+ #mod-quiz-edit div.question div.content div.qorder{
+ background-color:#ddf;
+}
+
+#mod-quiz-edit div.quizpage .pagecontent .pagestatus{
+ background-color:#eee;
+}
+#mod-quiz-edit .quizpagedelete img{
+ background-color:#d6d6d6;
+}
+#mod-quiz-edit div.quizpage .pagecontent form#addquestion{
+ background-color:#fff;
+}
+#mod-quiz-edit .questioncontentcontainer div.randomquestionqlist{
+ background-color:#eee;
+ color:#777;
+}
+#mod-quiz-edit .questioncontentcontainer div.randomquestionqlist .totalquestionsinrandomqcategory{
+ color:#000;
+}
+/*TODO: below applies to also question bank, so when
+question bank is adapted to the new UI, add the appropriate
+css id's of question bank*/
+#mod-quiz-edit .categoryinfo{
+ background-color:#eee;
+ border-bottom:1px solid #bbb;
+}
+#mod-quiz-edit .paging{
+ background-color:#ddd;
+}
+#mod-quiz-edit .questionsortoptions{
+ background-color:#ddd;
+}
+
+#mod-quiz-edit .paging a:hover{
+ background-color:#eef;
+}
+#mod-quiz-edit div.questionbank{
+ background-color:#e6e6ff;
+}
+#mod-quiz-edit .questionbank div.categoryquestionscontainer,.questionbank .categorysortopotionscontainer,.questionbank .categorypagingbarcontainer,.questionbank .categoryselectallcontainer{
+ background-color:#FFF;
+}
+#mod-quiz-edit div.question div.content div.questioncontrols{
+ background-color:#FFF;
+}
+#mod-quiz-edit div.editq div.question div.content{
+ background-color:#fff;
+}
+#mod-quiz-edit .questionbankwindow div.header a{
+ color:#FFF;
+}
+
+
/***
*** Modules: Resource
***/
color:#000;
}
+
text-decoration: underline;
}
-/***
+#mod-quiz-edit div.reorder .reordercontrols .moveselectedonpage{
+ text-align:right;
+}
+#mod-quiz-edit div.question div.qnum{
+ text-align:right;
+}
+#mod-quiz-edit div.reorder div.question div.qnum{
+ text-align:right;
+ font-size:1em;
+}
+#mod-quiz-edit div.editq div.question div.qnum{
+ font-size:1.5em;
+}
+#mod-quiz-edit .questionbankwindow div.header a{
+ text-decoration:underline;
+}
+#mod-quiz-edit div.questioncontentcontainer a{
+ text-decoration:underline;
+}
+
+#mod-quiz-edit div.questioncontentcontainer div.singlequestion a{
+ text-decoration:underline;
+}
+#mod-quiz-edit div.editq div.question div.content .singlequestion a .questionname,div.editq div.question div.content .singlequestion a .questiontext{
+ text-decoration:underline;
+}
+#mod-quiz-edit div.question div.content .questiontext,
+#categoryquestions .questiontext{
+ font-weight:bold;
+}
+#mod-quiz-edit div.question div.content div.questioncontrols{
+ text-align:right;
+}
+#mod-quiz-edit div.quizpage .pagecontent .pagestatus{
+ font-weight:bold;
+}
+#mod-quiz-edit div.question div.content .questiontype{
+ font-style:italic;
+}
+#mod-quiz-edit .questioncontentcontainer .randomquestioncategory{
+ font-weight:bold;
+}
+#mod-quiz-edit .categoryinfofield{
+ font-style:italic;
+}
+#mod-quiz-edit .categorynamefield{
+ font-weight:bold;
+}
+#mod-quiz-edit .questionbankwindow div.header{
+ font-weight:bold;
+}
+
+
+ /***
*** Modules: Resource
***/
#mod-quiz-review #middle-column {
height: 1%;
}
+#mod-quiz-edit div.question div.content .questionname,
+#categoryquestions .questionname{
+ /*ie6 shows this as an arrow if this is not specified*/
+ cursor: pointer;
+}
+#mod-quiz-edit #categoryquestions .questiontext{
+ /*ie6 shows this as an arrow if this is not specified*/
+ cursor: pointer;
+}
+#mod-quiz-edit div.tabtree a span img.iconsmall{
+ display:none;
+}
+
+#mod-quiz-edit div.question div.content .questiontext,#categoryquestions .questiontext{
+ width:50%;
+}
+#mod-quiz-edit div.question div.content .questionname,#categoryquestions .questionname{
+ width:20%;
+}
text-align: center;
}
-#redirect #message {
-
-}
-
-#redirect #continue {
-
-}
-
/* .clearfix {display: inline-table;} */
/* Hides from IE-mac \*/
margin-bottom: 0.5em;
}
-#mod-quiz-edit #page .controls,
-#mod-quiz-edit #page .quizattemptcounts
-{
- text-align: center;
-}
-#mod-quiz-edit .quizquestions h2 {
- margin-top: 0;
-}
-#mod-quiz-edit #showhidepagingcontrols {
- margin-top: 0.7em;
-}
-#mod-quiz-edit #showhidepagingcontrols .singlebutton {
- display: inline;
-}
.quizquestionlistcontrols {
text-align: center;
}
display: block;
margin: 0.5em 0;
}
+#mod-quiz-edit div.sideblock{
+ float:right;
+ width:30%;
+ right:0.3em;
+ padding-bottom:0.5em;
+ display:block;
+}
+
+#mod-quiz-edit div.quizcontents{
+ float:left;
+ width:70%;
+ display:block;
+}
+
+#mod-quiz-edit div.quizcontents,h2.main{
+ clear:left;
+}
+
+#mod-quiz-edit .addpage{
+ clear:both;
+ padding-top:0.3em;
+ float:right;
+ margin-right:2em;
+}
+
+#mod-quiz-edit h2.main{
+ display:inline;
+ padding-right:1em;
+}
+
+#mod-quiz-edit .statusdisplay{
+ clear:both;
+ display:block;
+ border:0.2em #FFF solid;
+ margin-bottom:0.3em;
+ margin-right:1em;
+ margin-top:0.3em;
+ padding:0.1em;
+}
+#mod-quiz-edit div.quizpage{
+ display:block;
+ clear:both;
+ width:100%;
+}
+
+#mod-quiz-edit div.quizpage span.pagetitle{
+ margin-top:0.3em;
+ float:left;
+ display:block;
+}
+
+#mod-quiz-edit div.reorder .reordercontrols .moveselectedonpage{
+ clear:right;
+ float:right;
+ padding:0.5em 0.3em;
+}
+
+#mod-quiz-edit div.reorder .reordercontrols .addnewpagesafterselected,#mod-quiz-edit .repaginatecommand{
+ float:right;
+ clear:right;
+ padding-right:1em;
+}
+
+#mod-quiz-edit div.reorder .reordercontrols .deleteselected{
+ float:right;
+ margin-right:1em;
+}
+
+#mod-quiz-edit div.reorder .reordercontrols{
+ clear:both;
+ padding-right:1em;
+ margin-top:0.5em;
+ padding-top:0.5em;
+ padding-bottom:0.5em;
+}
+
+#mod-quiz-edit div.quizpage .pagecontent{
+ margin-top:0.3em;
+ display:block;
+ float:left;
+ position:relative;
+ margin-left:0.3em;
+ border-left:solid #777 thin;
+ line-height:1.3em;
+ -webkit-border-radius:0.6em;
+ -webkit-border-radius-bottomleft:0;
+ -webkit-border-radius-topleft:0;
+ border-radius:0.6em;
+ border-radius-bottomleft:0;
+ border-radius-topleft:0;
+ width:88%;
+ padding:0 0 0.5em;
+}
+
+#mod-quiz-edit div.question{
+ clear:left;
+ width:100%;
+}
+
+#mod-quiz-edit div.question div.qnum{
+ display:block;
+ float:left;
+ width:1.4em;
+ padding-right:0.3em;
+ padding-left:0;
+ z-index:99;
+}
+
+#mod-quiz-edit div.reorder div.question div.qnum{
+ width:2.9em;
+ padding-top:0.1em;
+}
+/*edit tab*/
+#mod-quiz-edit div.editq div.question div.qnum{
+ padding-top:0.2em;
+}
+
+#mod-quiz-edit div.editq div.question{
+ padding-top:0.3em;
+}
+
+#mod-quiz-edit div.reorder div.question{
+ padding-top:0.2em;
+}
+
+#mod-quiz-edit div.question div.questioncontainer{
+ background-color:#ffc;
+}
+
+#mod-quiz-edit div.editq div.question div.content{
+ width:87%;
+ float:left;
+ position:relative;
+ -webkit-border-radius:0.6em;
+ -webkit-border-radius-bottomleft:0;
+ -webkit-border-radius-topleft:0;
+ border-radius:0.6em;
+ border-radius-bottomleft:0;
+ border-radius-topleft:0;
+ line-height:1.4em;
+ padding:0.5em;
+}
+
+#mod-quiz-edit .reorder div.question div.content{
+ width:87%;
+ float:left;
+ background-color:#fff;
+ position:relative;
+ -webkit-border-radius:0.3em;
+ -webkit-border-radius-bottomleft:0;
+ -webkit-border-radius-topleft:0;
+ border-radius:0.3em;
+ border-radius-bottomleft:0;
+ border-radius-topleft:0;
+ line-height:1.2em;
+ padding:0.1em;
+}
+
+#mod-quiz-edit div.question div.content div.points{
+ top:0.5em;
+ border-left:#FFF solid 0.4em;
+ width:7.5em;
+ padding:0.2em;
+}
+
+#mod-quiz-edit .questionbankwindow select#catmenu_jump{
+ /* In Opera9, IE6 the width of the
+ select obeys the width of its content
+ by default. This prevents that. */
+ width:100%;
+}
+
+#mod-quiz-edit .questionbankwindow div.header{
+ padding-top:0.2em;
+}
+
+#randomquestiondialog_c select{
+ width:100%;
+}
+
+
+#mod-quiz-edit div.question div.content div.points,
+ #mod-quiz-edit div.question div.content div.qorder{
+ line-height:1em;
+ float:right;
+ max-width:30%;
+ position:absolute;
+ right:50px;
+ -webkit-border-radius:0.2em;
+ -webkit-border-radius-bottomleft:0;
+ -webkit-border-radius-topleft:0;
+ border-radius:0.2em;
+ border-radius-bottomleft:0;
+ border-radius-topleft:0;
+ z-index:999;
+ display:block;
+ margin:0;
+}
+
+
+#mod-quiz-edit div.question div.content .editicon{
+ width:15px;
+}
+
+#mod-quiz-edit .editq div.questioncontentcontainer div.singlequestion img{
+ float:left;
+ padding-top:0.3em;
+ padding-right:0.3em;
+}
+
+
+#mod-quiz-edit div.question div.content .questionname,
+#categoryquestions .questionname{
+ white-space:nowrap;
+ text-overflow:ellipsis;
+ overflow:hidden;
+ zoom:1;
+ position:relative;
+ max-width:20%;
+ /*ie-only:*/
+ text-overflow:ellipsis;
+ /*opera-only*/
+ -o-text-overflow:ellipsis;
+}
+#mod-quiz-edit div.question div.content .singlequestion .questionname,
+#mod-quiz-edit div.question div.content .singlequestion .questiontext{
+ display:inline-block;
+}
+
+#mod-quiz-edit div.editq div.question div.content .singlequestion a .questionname,
+#mod-quiz-edit div.editq div.question div.content .singlequestion a .questiontext{
+ float:left;
+}
+
+#mod-quiz-edit .quizquestionlistcontrols{
+ display:inline;
+}
+
+#mod-quiz-edit div.question div.content .questiontext,
+#categoryquestions .questiontext{
+ -o-text-overflow:ellipsis;
+ text-overflow:ellipsis;
+ position:relative;
+ zoom:1;
+ padding-left:0.3em;
+ max-width:50%;
+ overflow:hidden;
+ white-space:nowrap;
+ text-overflow:ellipsis;
+}
+
+#mod-quiz-edit div.quizpage .pagecontent .pagestatus{
+ -webkit-border-radius-bottomright:0.3em;
+ -webkit-border-radius-topright:0.3em;
+ border-radius-bottomright:0.3em;
+ border-radius-topright:0.3em;
+ margin:0.3em;
+ padding:0.1em 0.1em 0.1em 0.3em;
+}
+
+#mod-quiz-edit div.question div.content .questiontype{
+ display:block;
+ clear:left;
+ float:left;
+}
+
+#mod-quiz-edit div.question div.content .questionpreview{
+ display:block;
+ float:left;
+ margin-left:0.3em;
+ padding-left:0.2em;
+ padding-right:0.2em;
+ background-color:#eee;
+}
+
+#mod-quiz-edit div.question div.content div.quiz_randomquestion .questionpreview{
+ display:inline;
+ float:none;
+}
+
+#mod-quiz-edit div.question div.content div.questioncontrols{
+ float:right;
+ width:45px;
+ position:absolute;
+ right:0.3em;
+ top:0;
+ z-index:999;
+ display:block;
+ padding:0.2em;
+}
+
+#mod-quiz-edit div.question div.content div.questioncontrols img.upwithoutdown{
+ padding-right:12px;
+ display:inline;
+}
+
+#mod-quiz-edit .quizpagedelete{
+ position:absolute;
+ top:0.2em;
+ right:0.2em;
+ display:inline;
+ z-index:999;
+}
+
+#mod-quiz-edit .quizpagedelete img{
+ background-color:#d6d6d6;
+ padding:0.5em;
+}
+
+#mod-quiz-edit .pagecontrols{
+ clear:both;
+ margin-left:0.5em;
+ padding-top:0.5em;
+}
+
+#mod-quiz-edit .pagecontrols .singlebutton{
+ float:left;
+}
+
+#mod-quiz-edit div.quizpage .pagecontent form#addquestion{
+ margin-right:1em;
+ -webkit-border-radius:0.2em;
+ border-radius:0.2em;
+ padding:0.3em;
+}
+
+#mod-quiz-edit div.quizpage .pagecontent form.randomquestionform{
+ padding-left:1em;
+}
+
+#mod-quiz-edit div.quizpage .pagecontent form.randomquestionform div{
+ /* it is a mystery why this has to be inline-table but
+ otherwise the layout gets screwed, even if
+ it is "inline" */
+ display:inline-table;
+}
+
+#mod-quiz-edit div.quizpage .pagecontent form.randomquestionform div input{
+ display:inline;
+}
+
+#mod-quiz-edit div.quizpage .pagecontent .adddescription{
+ clear:left;
+ margin-top:0.3em;
+}
+
+#mod-quiz-edit div.quizpage .pagecontent .addrandomquestion{
+ margin-top:0.3em;
+}
+
+/* a CSS class YUI container creates on the fly: */
+#mod-quiz-edit div#randomquestiondialog_c{
+ width:90%;
+}
+
+#mod-quiz-edit #repaginatedialog .hd{
+ display:none;
+}
+
+#mod-quiz-edit div#randomquestiondialog{
+ display:none;
+}
+
+#mod-quiz-edit div#randomquestiondialog_c .mform,
+#mod-quiz-edit div#repaginatedialog .mform{
+ margin-left:auto;
+ margin-right:auto;
+}
+
+#mod-quiz-edit div.container div.generalbox{
+ position:relative;
+ display:block;
+ border:0 none;
+ margin:0;
+ padding:0;
+}
+
+#mod-quiz-edit .questioncontentcontainer div.randomquestionqlist{
+ padding-left:0.2em;
+ padding-right:0.2em;
+ clear:both;
+ margin:0.5em;
+}
+
+
+#mod-quiz-edit .questioncontentcontainer div.randomquestionqlist ul{
+ list-style-type:none;
+ margin:0;
+ padding:0;
+}
+
+
+#mod-quiz-edit .reorder .questioncontentcontainer .randomquestioncategory,
+#mod-quiz-edit .reorder .questioncontentcontainer .randomquestionfromcategory,
+#mod-quiz-edit .reorder div.question div.content .questionpreview{
+ display:inline;
+ float:none;
+}
+
+#mod-quiz-edit .reorder .questioncontentcontainer{
+ position:relative;
+ overflow:hidden;
+ white-space:nowrap;
+}
+
+#mod-quiz-edit .reorder .questioncontentcontainer .randomquestioncategory{
+ overflow:hidden;
+ white-space:nowrap;
+}
+
+#mod-quiz-edit .reorder fieldset{
+ display:inline;
+}
+
+#mod-quiz-edit .questioncontentcontainer div.randomquestionqlist ul li{
+ clear:left;
+ width:100%;
+ overflow:hidden;
+ white-space:nowrap;
+}
+
+#mod-quiz-edit .questioncontentcontainer div.randomquestionqlist ul li span{
+ display:inline;
+}
+
+/*start question bank*/
+
+/*TODO: below applies to also question bank, so when
+question bank is adapted to the new UI, add the appropriate
+css id's of question bank*/
+#mod-quiz-edit .questionbankwindow .createnewquestion select,
+#mod-quiz-edit .questionbankwindow #catmenu select{
+ width:80%;
+}
+#mod-quiz-edit table#categoryquestions{
+ width:100%;
+ overflow:hidden;
+ table-layout:fixed;
+}
+
+#mod-quiz-edit table#categoryquestions td,#mod-quiz-edit table#categoryquestions th{
+ overflow:hidden;
+ white-space:nowrap;
+}
+
+#mod-quiz-edit table#categoryquestions col#qaction{
+ width:20%;
+}
+
+#mod-quiz-edit table#categoryquestions col#qextraactions{
+ width:40px;
+}
+
+#mod-quiz-edit table#categoryquestions .iconsmall{
+ padding-left:5px;
+}
+#mod-quiz-edit .categoryinfo{
+ padding:0.3em;
+}
+
+
+
+#mod-quiz-edit .paging{
+ margin-top:0;
+ margin-bottom:0;
+ display:block;
+}
+
+#mod-quiz-edit .questionsortoptions{
+ margin-top:0.3em;
+}
+
+#mod-quiz-edit .pagingbottom{
+ padding-bottom:0.3em;
+}
+
+#mod-quiz-edit div.questionbank form .invisiblefieldset{
+ clear:both;
+}
+
+#mod-quiz-edit div.createnewquestion{
+ padding-top:0.3em;
+ clear:left;
+}
+
+#mod-quiz-edit .sideblock .content{
+ padding:0;
+}
+
+#mod-quiz-edit .questionbank .categorysortopotionscontainer{
+ padding-top:0.5em;
+ margin-top:0.3em;
+}
+
+#mod-quiz-edit .questionbank .categoryselectallcontainer{
+ padding-bottom:0.5em;
+}
+
+#mod-quiz-edit .questionbank div.categoryquestionscontainer,
+#mod-quiz-edit .questionbank .categorysortopotionscontainer,
+#mod-quiz-edit .questionbank .categorypagingbarcontainer,
+#mod-quiz-edit .questionbank .categoryselectallcontainer{
+ padding-left:0.3em;
+ padding-right:0.3em;
+}
+
+#mod-quiz-edit .noquestionsincategory{
+ clear:both;
+ padding-top:1em;
+ padding-bottom:1em;
+}
+
+#mod-quiz-edit .modulespecificbuttonscontainer{
+ padding-left:0.3em;
+ padding-right:0.3em;
+}
+
+#mod-quiz-edit div#footer{
+ clear:both;
+ padding-top:1em;
+}
+
+#mod-quiz-edit #repaginatecommand{
+ display:none;
+}
+
+/*.usejs class is added via javascript so these will toggle if js is enabled*/
+#mod-quiz-edit .usejs #repaginatedialog{
+ display:none;
+}
+#mod-quiz-edit .usejs #repaginatedialog .hd{
+ display:block;
+}
+#mod-quiz-edit .usejs #repaginatedialog .bd{
+ padding:1em;
+}
+#mod-quiz-edit .usejs .repaginatecommand #repaginatecommand{
+ display:block;
+}
/***
*** Modules: Resource
/*******************************************************************
styles_moz.css
-
+
This CSS file uses the non-standard Mozilla CSS extensions
to add round corners to the current theme.
-moz-border-radius:3px;
}
-.categorybox, .categoryboxcontent,
+.categorybox, .categoryboxcontent,
.coursebox {
-moz-border-radius:10px;
}
#quiznavigation .qnbutton {
-moz-box-sizing: content-box;
}
+#mod-quiz-edit div.quizpage .pagecontent{
+ -moz-border-radius:0.6em;
+ -moz-border-radius-bottomleft:0;
+ -moz-border-radius-topleft:0;
+}
+#mod-quiz-edit .reorder div.question div.content{
+
+ -moz-border-radius:0.3em;
+ -moz-border-radius-bottomleft:0;
+ -moz-border-radius-topleft:0;
+}
+#mod-quiz-edit div.editq div.question div.content{
+ -moz-border-radius:0.6em;
+ -moz-border-radius-bottomleft:0;
+ -moz-border-radius-topleft:0;
+}
+#mod-quiz-edit div.question div.content div.points,
+ #mod-quiz-edit div.question div.content div.qorder{
+ -moz-border-radius:0.2em;
+ -moz-border-radius-bottomleft:0;
+ -moz-border-radius-topleft:0;
+}
+#mod-quiz-edit div.quizpage .pagecontent .pagestatus{
+ -moz-border-radius-bottomright:0.3em;
+ -moz-border-radius-topright:0.3em;
+}
+#mod-quiz-edit div.quizpage .pagecontent form#addquestion{
+ -moz-border-radius:0.2em;
+}
\ No newline at end of file