any page not seen before
*/
if (!defined("LESSON_UNSEENPAGE")) {
define("LESSON_UNSEENPAGE", 1); // Next page -> any page not seen before
}
/**
* Next page -> any page not answered correctly
*/
if (!defined("LESSON_UNANSWEREDPAGE")) {
define("LESSON_UNANSWEREDPAGE", 2); // Next page -> any page not answered correctly
}
/**
* Define different lesson flows for next page
*/
$LESSON_NEXTPAGE_ACTION = array (0 => get_string("normal", "lesson"),
LESSON_UNSEENPAGE => get_string("showanunseenpage", "lesson"),
LESSON_UNANSWEREDPAGE => get_string("showanunansweredpage", "lesson") );
// Lesson jump types defined
// TODO: instead of using define statements, create an array with all the jump values
/**
* Jump to Next Page
*/
if (!defined("LESSON_NEXTPAGE")) {
define("LESSON_NEXTPAGE", -1);
}
/**
* End of Lesson
*/
if (!defined("LESSON_EOL")) {
define("LESSON_EOL", -9);
}
/**
* Jump to an unseen page within a branch and end of branch or end of lesson
*/
if (!defined("LESSON_UNSEENBRANCHPAGE")) {
define("LESSON_UNSEENBRANCHPAGE", -50);
}
/**
* Jump to Previous Page
*/
if (!defined("LESSON_PREVIOUSPAGE")) {
define("LESSON_PREVIOUSPAGE", -40);
}
/**
* Jump to a random page within a branch and end of branch or end of lesson
*/
if (!defined("LESSON_RANDOMPAGE")) {
define("LESSON_RANDOMPAGE", -60);
}
/**
* Jump to a random Branch
*/
if (!defined("LESSON_RANDOMBRANCH")) {
define("LESSON_RANDOMBRANCH", -70);
}
/**
* Cluster Jump
*/
if (!defined("LESSON_CLUSTERJUMP")) {
define("LESSON_CLUSTERJUMP", -80);
}
/**
* Undefined
*/
if (!defined("LESSON_UNDEFINED")) {
define("LESSON_UNDEFINED", -99);
}
// Lesson question types defined
/**
* Short answer question type
*/
if (!defined("LESSON_SHORTANSWER")) {
define("LESSON_SHORTANSWER", "1");
}
/**
* True/False question type
*/
if (!defined("LESSON_TRUEFALSE")) {
define("LESSON_TRUEFALSE", "2");
}
/**
* Multichoice question type
*
* If you change the value of this then you need
* to change it in restorelib.php as well.
*/
if (!defined("LESSON_MULTICHOICE")) {
define("LESSON_MULTICHOICE", "3");
}
/**
* Random question type - not used
*/
if (!defined("LESSON_RANDOM")) {
define("LESSON_RANDOM", "4");
}
/**
* Matching question type
*
* If you change the value of this then you need
* to change it in restorelib.php, in mysql.php
* and postgres7.php as well.
*/
if (!defined("LESSON_MATCHING")) {
define("LESSON_MATCHING", "5");
}
/**
* Not sure - not used
*/
if (!defined("LESSON_RANDOMSAMATCH")) {
define("LESSON_RANDOMSAMATCH", "6");
}
/**
* Not sure - not used
*/
if (!defined("LESSON_DESCRIPTION")) {
define("LESSON_DESCRIPTION", "7");
}
/**
* Numerical question type
*/
if (!defined("LESSON_NUMERICAL")) {
define("LESSON_NUMERICAL", "8");
}
/**
* Multichoice with multianswer question type
*/
if (!defined("LESSON_MULTIANSWER")) {
define("LESSON_MULTIANSWER", "9");
}
/**
* Essay question type
*/
if (!defined("LESSON_ESSAY")) {
define("LESSON_ESSAY", "10");
}
/**
* Lesson question type array.
* Contains all question types used
*/
$LESSON_QUESTION_TYPE = array ( LESSON_MULTICHOICE => get_string("multichoice", "quiz"),
LESSON_TRUEFALSE => get_string("truefalse", "quiz"),
LESSON_SHORTANSWER => get_string("shortanswer", "quiz"),
LESSON_NUMERICAL => get_string("numerical", "quiz"),
LESSON_MATCHING => get_string("match", "quiz"),
LESSON_ESSAY => get_string("essay", "lesson")
// LESSON_DESCRIPTION => get_string("description", "quiz"),
// LESSON_RANDOM => get_string("random", "quiz"),
// LESSON_RANDOMSAMATCH => get_string("randomsamatch", "quiz"),
// LESSON_MULTIANSWER => get_string("multianswer", "quiz"),
);
// Non-question page types
/**
* Branch Table page
*/
if (!defined("LESSON_BRANCHTABLE")) {
define("LESSON_BRANCHTABLE", "20");
}
/**
* End of Branch page
*/
if (!defined("LESSON_ENDOFBRANCH")) {
define("LESSON_ENDOFBRANCH", "21");
}
/**
* Start of Cluster page
*/
if (!defined("LESSON_CLUSTER")) {
define("LESSON_CLUSTER", "30");
}
/**
* End of Cluster page
*/
if (!defined("LESSON_ENDOFCLUSTER")) {
define("LESSON_ENDOFCLUSTER", "31");
}
// other variables...
/**
* Flag for the editor for the answer textarea.
*/
if (!defined("LESSON_ANSWER_EDITOR")) {
define("LESSON_ANSWER_EDITOR", "1");
}
/**
* Flag for the editor for the response textarea.
*/
if (!defined("LESSON_RESPONSE_EDITOR")) {
define("LESSON_RESPONSE_EDITOR", "2");
}
//////////////////////////////////////////////////////////////////////////////////////
/// Any other lesson functions go here. Each of them must have a name that
/// starts with lesson_
/**
* Print the standard header for lesson module
*
* @param object $cm Course module record object
* @param object $course Couse record object
* @param object $lesson Lesson module record object
* @param string $currenttab Current tab for the lesson tabs
* @param boolean $printheading Print the a heading with the lesson name
* @return void
**/
function lesson_print_header($cm, $course, $lesson, $currenttab = '') {
global $CFG, $USER;
$strlessons = get_string('modulenameplural', 'lesson');
$strlesson = get_string('modulename', 'lesson');
$strname = format_string($lesson->name, true);
$context = get_context_instance(CONTEXT_MODULE, $cm->id);
// Changed the update_module_button and added another button when a teacher is checking the navigation of the lesson
if (has_capability('mod/lesson:edit', $context)) {
$button = update_module_button($cm->id, $course->id, $strlesson);
if ($currenttab == 'view') {
if (!$pageid = optional_param('pageid', 0, PARAM_INT)) {
$pageid = get_field('lesson_pages', 'id', 'lessonid', $lesson->id, 'prevpageid', 0);
}
if (!empty($pageid) and $pageid != LESSON_EOL) {
$button = '
'.$button.
'
'.
'
';
}
}
} else {
$button = '';
}
/// Header setup
if ($course->category) {
$navigation = "wwwroot/course/view.php?id=$course->id\" title=\"$course->fullname\">$course->shortname ->";
} else {
$navigation = '';
}
/// Print header, heading, tabs and messages
print_header("$course->shortname: $strname", $course->fullname,
"$navigation id\" title=\"$strlessons\">$strlessons -> $strname",
'', '', true, $button, navmenu($course, $cm));
if (has_capability('mod/lesson:manage')) {
print_heading_with_help(format_string($lesson->name, true), "overview", "lesson");
} else {
print_heading($lesson->name);
}
if (!empty($currenttab) and has_capability('mod/lesson:manage', $context)) {
include($CFG->dirroot.'/mod/lesson/tabs.php');
}
lesson_print_messages();
}
/**
* Returns course module, course and module instance given
* either the course module ID or a lesson module ID.
*
* @param int $cmid Course Module ID
* @param int $lessonid Lesson module instance ID
* @return array array($cm, $course, $lesson)
**/
function lesson_get_basics($cmid = 0, $lessonid = 0) {
if ($cmid) {
if (!$cm = get_coursemodule_from_id('lesson', $cmid)) {
error('Course Module ID was incorrect');
}
if (!$course = get_record('course', 'id', $cm->course)) {
error('Course is misconfigured');
}
if (!$lesson = get_record('lesson', 'id', $cm->instance)) {
error('Course module is incorrect');
}
} else if ($lessonid) {
if (!$lesson = get_record('lesson', 'id', $lessonid)) {
error('Course module is incorrect');
}
if (!$course = get_record('course', 'id', $lesson->course)) {
error('Course is misconfigured');
}
if (!$cm = get_coursemodule_from_instance('lesson', $lesson->id, $course->id)) {
error('Course Module ID was incorrect');
}
} else {
error('No course module ID or lesson ID were passed');
}
return array($cm, $course, $lesson);
}
/**
* Sets a message to be printed. Messages are printed
* by calling {@link lesson_print_messages()}.
*
* @uses $SESSION
* @param string $message The message to be printed
* @param string $class Class to be passed to {@link notify()}. Usually notifyproblem or notifysuccess.
* @param string $align Alignment of the message
* @return boolean
**/
function lesson_set_message($message, $class="notifyproblem", $align='center') {
global $SESSION;
if (empty($SESSION->lesson_messages) or !is_array($SESSION->lesson_messages)) {
$SESSION->lesson_messages = array();
}
$SESSION->lesson_messages[] = array($message, $class, $align);
return true;
}
/**
* Print all set messages.
*
* See {@link lesson_set_message()} for setting messages.
*
* Uses {@link notify()} to print the messages.
*
* @uses $SESSION
* @return boolean
**/
function lesson_print_messages() {
global $SESSION;
if (empty($SESSION->lesson_messages)) {
// No messages to print
return true;
}
foreach($SESSION->lesson_messages as $message) {
notify($message[0], $message[1], $message[2]);
}
// Reset
unset($SESSION->lesson_messages);
return true;
}
/**
* Prints a lesson link that submits a form.
*
* If Javascript is disabled, then a regular submit button is printed
*
* @return mixed boolean/html
**/
function lesson_print_submit_link($name, $form, $align = 'center', $class='standardbutton', $title = '', $id = '', $return = false) {
if (!empty($id)) {
$id = " id=\"$id\"";
}
if (empty($title)) {
$title = $name;
}
$output = "
\n";
$output .= "
\n";
$output .= "
\n";
if ($return) {
return $output;
} else {
echo $output;
return true;
}
}
/**
* Prints a time remaining in the following format: H:MM:SS
*
* @param int $starttime Time when the lesson started
* @param int $maxtime Length of the lesson
* @param boolean $return Return output switch
* @return mixed boolean/string
**/
function lesson_print_time_remaining($starttime, $maxtime, $return = false) {
// Calculate hours, minutes and seconds
$timeleft = $starttime + $maxtime * 60 - time();
$hours = floor($timeleft/3600);
$timeleft = $timeleft - ($hours * 3600);
$minutes = floor($timeleft/60);
$secs = $timeleft - ($minutes * 60);
if ($minutes < 10) {
$minutes = "0$minutes";
}
if ($secs < 10) {
$secs = "0$secs";
}
$output = array();
$output[] = $hours;
$output[] = $minutes;
$output[] = $secs;
$output = implode(':', $output);
if ($return) {
return $output;
} else {
echo $output;
return true;
}
}
/**
* Given some question info and some data about the the answers
* this function parses, organises and saves the question
*
* This is only used when IMPORTING questions and is only called
* from format.php
* Lifted from mod/quiz/lib.php -
* 1. all reference to oldanswers removed
* 2. all reference to quiz_multichoice table removed
* 3. In SHORTANSWER questions usecase is store in the qoption field
* 4. In NUMERIC questions store the range as two answers
* 5. TRUEFALSE options are ignored
* 6. For MULTICHOICE questions with more than one answer the qoption field is true
*
* @param opject $question Contains question data like question, type and answers.
* @return object Returns $result->error or $result->notice.
**/
function lesson_save_question_options($question) {
$timenow = time();
switch ($question->qtype) {
case LESSON_SHORTANSWER:
$answers = array();
$maxfraction = -1;
// Insert all the new answers
foreach ($question->answer as $key => $dataanswer) {
if ($dataanswer != "") {
$answer = new stdClass;
$answer->lessonid = $question->lessonid;
$answer->pageid = $question->id;
if ($question->fraction[$key] >=0.5) {
$answer->jumpto = LESSON_NEXTPAGE;
}
$answer->timecreated = $timenow;
$answer->grade = $question->fraction[$key] * 100;
$answer->answer = $dataanswer;
$answer->response = $question->feedback[$key];
if (!$answer->id = insert_record("lesson_answers", $answer)) {
$result->error = "Could not insert shortanswer quiz answer!";
return $result;
}
$answers[] = $answer->id;
if ($question->fraction[$key] > $maxfraction) {
$maxfraction = $question->fraction[$key];
}
}
}
/// Perform sanity checks on fractional grades
if ($maxfraction != 1) {
$maxfraction = $maxfraction * 100;
$result->notice = get_string("fractionsnomax", "quiz", $maxfraction);
return $result;
}
break;
case LESSON_NUMERICAL: // Note similarities to SHORTANSWER
$answers = array();
$maxfraction = -1;
// for each answer store the pair of min and max values even if they are the same
foreach ($question->answer as $key => $dataanswer) {
if ($dataanswer != "") {
$answer = new stdClass;
$answer->lessonid = $question->lessonid;
$answer->pageid = $question->id;
$answer->jumpto = LESSON_NEXTPAGE;
$answer->timecreated = $timenow;
$answer->grade = $question->fraction[$key] * 100;
$min = $question->answer[$key] - $question->tolerance[$key];
$max = $question->answer[$key] + $question->tolerance[$key];
$answer->answer = $min.":".$max;
// $answer->answer = $question->min[$key].":".$question->max[$key]; original line for min/max
$answer->response = $question->feedback[$key];
if (!$answer->id = insert_record("lesson_answers", $answer)) {
$result->error = "Could not insert numerical quiz answer!";
return $result;
}
$answers[] = $answer->id;
if ($question->fraction[$key] > $maxfraction) {
$maxfraction = $question->fraction[$key];
}
}
}
/// Perform sanity checks on fractional grades
if ($maxfraction != 1) {
$maxfraction = $maxfraction * 100;
$result->notice = get_string("fractionsnomax", "quiz", $maxfraction);
return $result;
}
break;
case LESSON_TRUEFALSE:
// the truth
$answer->lessonid = $question->lessonid;
$answer->pageid = $question->id;
$answer->timecreated = $timenow;
$answer->answer = get_string("true", "quiz");
$answer->grade = $question->answer * 100;
if ($answer->grade > 50 ) {
$answer->jumpto = LESSON_NEXTPAGE;
}
if (isset($question->feedbacktrue)) {
$answer->response = $question->feedbacktrue;
}
if (!$true->id = insert_record("lesson_answers", $answer)) {
$result->error = "Could not insert quiz answer \"true\")!";
return $result;
}
// the lie
$answer = new stdClass;
$answer->lessonid = $question->lessonid;
$answer->pageid = $question->id;
$answer->timecreated = $timenow;
$answer->answer = get_string("false", "quiz");
$answer->grade = (1 - (int)$question->answer) * 100;
if ($answer->grade > 50 ) {
$answer->jumpto = LESSON_NEXTPAGE;
}
if (isset($question->feedbackfalse)) {
$answer->response = $question->feedbackfalse;
}
if (!$false->id = insert_record("lesson_answers", $answer)) {
$result->error = "Could not insert quiz answer \"false\")!";
return $result;
}
break;
case LESSON_MULTICHOICE:
$totalfraction = 0;
$maxfraction = -1;
$answers = array();
// Insert all the new answers
foreach ($question->answer as $key => $dataanswer) {
if ($dataanswer != "") {
$answer = new stdClass;
$answer->lessonid = $question->lessonid;
$answer->pageid = $question->id;
$answer->timecreated = $timenow;
$answer->grade = $question->fraction[$key] * 100;
// changed some defaults
/* Original Code
if ($answer->grade > 50 ) {
$answer->jumpto = LESSON_NEXTPAGE;
}
Replaced with: */
if ($answer->grade > 50 ) {
$answer->jumpto = LESSON_NEXTPAGE;
$answer->score = 1;
}
// end Replace
$answer->answer = $dataanswer;
$answer->response = $question->feedback[$key];
if (!$answer->id = insert_record("lesson_answers", $answer)) {
$result->error = "Could not insert multichoice quiz answer! ";
return $result;
}
// for Sanity checks
if ($question->fraction[$key] > 0) {
$totalfraction += $question->fraction[$key];
}
if ($question->fraction[$key] > $maxfraction) {
$maxfraction = $question->fraction[$key];
}
}
}
/// Perform sanity checks on fractional grades
if ($question->single) {
if ($maxfraction != 1) {
$maxfraction = $maxfraction * 100;
$result->notice = get_string("fractionsnomax", "quiz", $maxfraction);
return $result;
}
} else {
$totalfraction = round($totalfraction,2);
if ($totalfraction != 1) {
$totalfraction = $totalfraction * 100;
$result->notice = get_string("fractionsaddwrong", "quiz", $totalfraction);
return $result;
}
}
break;
case LESSON_MATCHING:
$subquestions = array();
$i = 0;
// Insert all the new question+answer pairs
foreach ($question->subquestions as $key => $questiontext) {
$answertext = $question->subanswers[$key];
if (!empty($questiontext) and !empty($answertext)) {
$answer = new stdClass;
$answer->lessonid = $question->lessonid;
$answer->pageid = $question->id;
$answer->timecreated = $timenow;
$answer->answer = $questiontext;
$answer->response = $answertext;
if ($i == 0) {
// first answer contains the correct answer jump
$answer->jumpto = LESSON_NEXTPAGE;
}
if (!$subquestion->id = insert_record("lesson_answers", $answer)) {
$result->error = "Could not insert quiz match subquestion!";
return $result;
}
$subquestions[] = $subquestion->id;
$i++;
}
}
if (count($subquestions) < 3) {
$result->notice = get_string("notenoughsubquestions", "quiz");
return $result;
}
break;
case LESSON_RANDOMSAMATCH:
$options->question = $question->id;
$options->choose = $question->choose;
if ($existing = get_record("quiz_randomsamatch", "question", $options->question)) {
$options->id = $existing->id;
if (!update_record("quiz_randomsamatch", $options)) {
$result->error = "Could not update quiz randomsamatch options!";
return $result;
}
} else {
if (!insert_record("quiz_randomsamatch", $options)) {
$result->error = "Could not insert quiz randomsamatch options!";
return $result;
}
}
break;
case LESSON_MULTIANSWER:
if (!$oldmultianswers = get_records("quiz_multianswers", "question", $question->id, "id ASC")) {
$oldmultianswers = array();
}
// Insert all the new multi answers
foreach ($question->answers as $dataanswer) {
if ($oldmultianswer = array_shift($oldmultianswers)) { // Existing answer, so reuse it
$multianswer = $oldmultianswer;
$multianswer->positionkey = $dataanswer->positionkey;
$multianswer->norm = $dataanswer->norm;
$multianswer->answertype = $dataanswer->answertype;
if (! $multianswer->answers = quiz_save_multianswer_alternatives
($question->id, $dataanswer->answertype,
$dataanswer->alternatives, $oldmultianswer->answers))
{
$result->error = "Could not update multianswer alternatives! (id=$multianswer->id)";
return $result;
}
if (!update_record("quiz_multianswers", $multianswer)) {
$result->error = "Could not update quiz multianswer! (id=$multianswer->id)";
return $result;
}
} else { // This is a completely new answer
$multianswer = new stdClass;
$multianswer->question = $question->id;
$multianswer->positionkey = $dataanswer->positionkey;
$multianswer->norm = $dataanswer->norm;
$multianswer->answertype = $dataanswer->answertype;
if (! $multianswer->answers = quiz_save_multianswer_alternatives
($question->id, $dataanswer->answertype,
$dataanswer->alternatives))
{
$result->error = "Could not insert multianswer alternatives! (questionid=$question->id)";
return $result;
}
if (!insert_record("quiz_multianswers", $multianswer)) {
$result->error = "Could not insert quiz multianswer!";
return $result;
}
}
}
break;
case LESSON_RANDOM:
break;
case LESSON_DESCRIPTION:
break;
default:
$result->error = "Unsupported question type ($question->qtype)!";
return $result;
break;
}
return true;
}
/**
* Given an array of value, creates a popup menu to be part of a form.
*
* @param array $options Used to create the popup menu values ( $options["value"]["label"] ).
* @param string $name Name of the select form element.
* @param string $selected Current value selected in the popup menu.
* @param string $nothing If set, used as the first value in the popup menu.
* @param string $script OnChange javascript code.
* @param string|int $nothingvalue Value of the $nothing parameter.
* @param boolean $return False: Print out the popup menu automatically True: Return the popup menu.
* @return string May return the popup menu as a string.
* @todo replace the use of this function with choose_from_menu in lib/weblib.php
**/
function lesson_choose_from_menu ($options, $name, $selected="", $nothing="choose", $script="", $nothingvalue="0", $return=false) {
if ($nothing == "choose") {
$nothing = get_string("choose")."...";
}
if ($script) {
$javascript = "onChange=\"$script\"";
} else {
$javascript = "";
}
$output = "