diff --git a/lang/en/help/lesson/grade.html b/lang/en/help/lesson/grade.html
new file mode 100644
index 00000000000..ded21426517
--- /dev/null
+++ b/lang/en/help/lesson/grade.html
@@ -0,0 +1,7 @@
+
The Grade of the Lesson
+
+
This value determines the maximum grade which can be awarded in
+ the lesson. The range is 0 to 100%. This value can be changed at
+ any time during the lesson. Any change has an immediate effect in
+ the Grades page and on the grades shown to the students in various
+ lists.
diff --git a/lang/en/help/lesson/jumpto.html b/lang/en/help/lesson/jumpto.html
new file mode 100644
index 00000000000..de7fc2e27ba
--- /dev/null
+++ b/lang/en/help/lesson/jumpto.html
@@ -0,0 +1,13 @@
+
The Jump-to Link
+
+
Each answer has a Jump-to link. When this answer is chosen, the answer's response
+ is shown to the student. Atfer that the student sees the page given in the Jump-to
+ link. This link can be either relative or absolute. Relative links are This
+ page and Next page. This page means that the student sees the
+ current page again. Next page shows the page which follows this page in the
+ logical order of pages. An absolute page link is specified by choosing the page's
+ title.
+
Note that a (relative) Next page Jump-to link may show a different page
+ after pages have been moved. Whereas Jump-to links which use page titles
+ always show the same page after pages have been moved.
+
diff --git a/lang/en/help/lesson/maxanswers.html b/lang/en/help/lesson/maxanswers.html
new file mode 100644
index 00000000000..a72db12f7f4
--- /dev/null
+++ b/lang/en/help/lesson/maxanswers.html
@@ -0,0 +1,7 @@
+
The Maximum Number of Answers in a Lesson
+
+
This value determines the maximum number of answers the teacher can use.
+ The default value is 4. If the lesson uses only TRUE or FALSE
+ questions throughout then it is sensible to set this value to 2.
+
+
It is safe to change this value in a lesson with existing content.
A lesson delivers content in an interesting and flexible way. It consists of a
+ number of pages. Each page normally ends with a question and a number of
+ possible answers. Depending on the student's choice of answer they either
+ progress to the next page or are taken back to a previous page. Navigation
+ through the lesson can be straight forward or complex, depending largely
+ on the structure of the material being presented.
+
+
diff --git a/lang/en/help/lesson/overview.html b/lang/en/help/lesson/overview.html
new file mode 100644
index 00000000000..0083ff2e817
--- /dev/null
+++ b/lang/en/help/lesson/overview.html
@@ -0,0 +1,55 @@
+
Overview
+
+
+
A lesson is made up of a number of pages.
+
A page contains some content and it normally ends with a question.
+
Each page normally has a set of answers.
+
Each answer can have a short piece of text which is displayed if the answer is
+ chosen. This piece of text is called the response.
+
Also associated with each answer is a jump. The jump can be relative -
+ this page, next page - or absolute - specifying any one of the pages in the
+ lesson or the end of the lesson.
+
By default, the first answer jumps to the next page in the lesson.
+ The subsequent answers jump to the same page. That is, the student is shown
+ the same page of the lesson again if they do not chose the first answer.
+
The next page is determined by the lesson's logical order. This is
+ the order of the pages as seen by the teacher. This order can be altered
+ by moving pages within the lesson.
+
The lesson also has a navigation order. This is the order of the
+ pages as seen by the students. This is determined by the jumps specified
+ for individual answers and it can be very different from the logical order.
+ (Although if the jumps are not changed from their default values
+ the two are strongly related.) The teacher has the option to check the
+ navigation order.
+
When displayed to the students, the answers are always shuffled. That is, the
+ first answer from the teacher's point of view will not necessarily be the
+ first answer in the list shown to the students. (Further, each time the same
+ set of answers is displayed they are likely to appear in a different order.)
+
The number of answers can vary from page to page. For example, it is allowed
+ that some pages can end with a true/false question while others have questions
+ with one correct answer and three, say, distractors.
+
It is possible to set up a page without any answers. The students are shown
+ a Continue link instead of the set of shuffled answers.
+
For the purposes of grading the lessons, correct answers are ones which
+ jump to a page which is further down the logical order than the current page.
+ Wrong answers are ones which either jump to the same page or to a page
+ further up the logical order than the current page. Thus, if the jumps are
+ not changed, the first answer is a correct answer and the other answers are
+ wrong answers.
+
Questions can have more than one correct answer. For example, if two of the answers
+ jump to the next page then either answer is taken as a correct answer. (Although
+ the same destination page is shown to the students, the responses shown on the way
+ to that page may well be different for the two answers.)
+
In the teacher's view of the lesson the correct answers have underlined Answer
+ Labels.
+
The end of the lesson is reached by either jumping to that location explicitly
+ or by jumping to the next page from the last (logical) page of the lesson. When the
+ end of the lesson is reached, the student receives a congratulations message and is
+ shown their grade. The grade is (the number of correct answers checked / number of
+ pages seen) * the grade of the lesson.
+
If the end of the lesson is not reached, when the student goes into the
+ lesson they are given the choice of starting at the begining or picking up the lesson
+ where they answered their last correct answer.
+
For a lesson which allow re-takes, students are allowed to re-take the lesson until
+ they have achieved the maximum grade.
+
diff --git a/lang/en/help/lesson/retake.html b/lang/en/help/lesson/retake.html
new file mode 100644
index 00000000000..a0027e69b74
--- /dev/null
+++ b/lang/en/help/lesson/retake.html
@@ -0,0 +1,16 @@
+
Allowing the Students to Re-take the Lesson
+
+
This setting determines whether the students can take the lesson more than once
+ or only once. The teacher may decide that the lesson contains material which
+ the students ought to know throughly. In which case repeated viewings of the
+ lesson should be allowed. If, however, the material is used more like an exam
+ then the students should not be allowed to re-take the lesson.
+
+
When the students are allowed to re-take the lesson, the grades shown
+ in the Grades page are the grades from their best attempts of the lesson.
+ However, the Question Analysis always uses the answers from the
+ first attempts of the lesson, subsequent attempts are ignored.
+
+
By default this option is Yes, meaning that students are allowed to re-take
+ the lesson. It is expected that only in exceptional circumstances will this
+ option be set to No.
diff --git a/lang/en/lesson.php b/lang/en/lesson.php
new file mode 100644
index 00000000000..7fbd87e3515
--- /dev/null
+++ b/lang/en/lesson.php
@@ -0,0 +1,39 @@
+Do you want to start at the last page you saw?";
+
+?>
diff --git a/mod/lesson/backuplib.php b/mod/lesson/backuplib.php
new file mode 100644
index 00000000000..07ce4d30072
--- /dev/null
+++ b/mod/lesson/backuplib.php
@@ -0,0 +1,258 @@
+id) |
+ // | |
+ // | lesson_grades
+ // | (UL, pk->id,fk->lessonid)
+ // lesson_pages
+ // (pk->id,fk->lessonid)
+ // |
+ // |
+ // |
+ // lesson_answers
+ // (pk->id,fk->pageid)
+ // |
+ // |
+ // |
+ // lesson_attempts
+ // (UL,pk->id,fk->answerid)
+ //
+ // Meaning: pk->primary key field of the table
+ // fk->foreign key to link with parent
+ // nt->nested field (recursive data)
+ // CL->course level info
+ // UL->user level info
+ // files->table may have files)
+ //
+ //-----------------------------------------------------------
+
+ //This function executes all the backup procedure about this mod
+ function lesson_backup_mods($bf, $preferences) {
+
+ global $CFG;
+
+ $status = true;
+
+ //Iterate over lesson table
+ $lessons = get_records("lesson", "course", $preferences->backup_course, "id");
+ if ($lessons) {
+ foreach ($lessons as $lesson) {
+ //Start mod
+ fwrite ($bf,start_tag("MOD",3,true));
+ //Print lesson data
+ fwrite ($bf,full_tag("ID",4,false,$lesson->id));
+ fwrite ($bf,full_tag("MODTYPE",4,false,"lesson"));
+ fwrite ($bf,full_tag("NAME",4,false,$lesson->name));
+ fwrite ($bf,full_tag("GRADE",4,false,$lesson->grade));
+ fwrite ($bf,full_tag("MAXANSWERS",4,false,$lesson->maxanswers));
+ fwrite ($bf,full_tag("RETAKE",4,false,$lesson->retake));
+ fwrite ($bf,full_tag("AVAILABLE",4,false,$lesson->available));
+ fwrite ($bf,full_tag("DEADLINE",4,false,$lesson->deadline));
+ fwrite ($bf,full_tag("TIMEMODIFIED",4,false,$lesson->timemodified));
+ //Now we backup lesson pages
+ $status = backup_lesson_pages($bf,$preferences,$lesson->id);
+ //if we've selected to backup users info, then backup grades
+ if ($status) {
+ if ($preferences->mods["lesson"]->userinfo) {
+ $status = backup_lesson_grades($bf, $preferences, $lesson->id);
+ }
+ //End mod
+ $status =fwrite ($bf,end_tag("MOD",3,true));
+ }
+ }
+ }
+ return $status;
+ }
+
+ //Backup lesson_pages contents (executed from lesson_backup_mods)
+ function backup_lesson_pages ($bf, $preferences, $lessonid) {
+
+ global $CFG;
+
+ $status = true;
+
+ // run through the pages in their logical order, get the first page
+ if ($page = get_record_select("lesson_pages", "lessonid = $lessonid AND prevpageid = 0")) {
+ //Write start tag
+ $status =fwrite ($bf,start_tag("PAGES",4,true));
+ //Iterate over each page
+ while (true) {
+ //Start of page
+ $status =fwrite ($bf,start_tag("PAGE",5,true));
+ //Print page contents (prevpageid and nextpageid not needed)
+ fwrite ($bf,full_tag("PAGEID",6,false,$page->id)); // needed to fix (absolute) jumps
+ fwrite ($bf,full_tag("TIMECREATED",6,false,$page->timecreated));
+ fwrite ($bf,full_tag("TIMEMODIFIED",6,false,$page->timemodified));
+ fwrite ($bf,full_tag("TITLE",6,false,$page->title));
+ fwrite ($bf,full_tag("CONTENTS",6,false,$page->contents));
+ //Now we backup lesson answers for this page
+ $status = backup_lesson_answers($bf, $preferences, $page->id);
+ //End of page
+ $status =fwrite ($bf,end_tag("PAGE",5,true));
+ // move to the next (logical) page
+ if ($page->nextpageid) {
+ if (!$page = get_record("lesson_pages", "id", $page->nextpageid)) {
+ error("Lesson Backup: Next page not found!");
+ }
+ } else {
+ // last page reached
+ break;
+ }
+
+ }
+ //Write end tag
+ $status =fwrite ($bf,end_tag("PAGES",4,true));
+ }
+ return $status;
+ }
+
+ //Backup lesson_answers contents (executed from backup_lesson_pages)
+ function backup_lesson_answers($bf,$preferences,$pageno) {
+
+ global $CFG;
+
+ $status = true;
+
+ $lesson_answers = get_records("lesson_answers", "pageid", $pageno);
+
+ //If there is lesson_answers
+ if ($lesson_answers) {
+ //Write start tag
+ $status =fwrite ($bf,start_tag("ANSWERS",6,true));
+ //Iterate over each element
+ foreach ($lesson_answers as $answer) {
+ //Start answer
+ $status =fwrite ($bf,start_tag("ANSWER",7,true));
+ //Print answer contents
+ fwrite ($bf,full_tag("JUMPTO",8,false,$answer->jumpto));
+ fwrite ($bf,full_tag("TIMECREATED",8,false,$answer->timecreated));
+ fwrite ($bf,full_tag("TIMEMODIFIED",8,false,$answer->timemodified));
+ fwrite ($bf,full_tag("ANSWERTEXT",8,false,$answer->answer));
+ fwrite ($bf,full_tag("RESPONSE",8,false,$answer->response));
+ //Now we backup any lesson attempts (if student data required)
+ if ($preferences->mods["lesson"]->userinfo) {
+ $status = backup_lesson_attempts($bf,$preferences,$answer->id);
+ }
+ //End rubric
+ $status =fwrite ($bf,end_tag("ANSWER",7,true));
+ }
+ //Write end tag
+ $status =fwrite ($bf,end_tag("ANSWERS",6,true));
+ }
+ return $status;
+ }
+
+ //Backup lesson_attempts contents (executed from lesson_backup_answers)
+ function backup_lesson_attempts ($bf,$preferences,$answerid) {
+
+ global $CFG;
+
+ $status = true;
+
+ $lesson_attempts = get_records("lesson_attempts","answerid", $answerid);
+ //If there are attempts
+ if ($lesson_attempts) {
+ //Write start tag
+ $status =fwrite ($bf,start_tag("ATTEMPTS",4,true));
+ //Iterate over each attempt
+ foreach ($lesson_attempts as $attempt) {
+ //Start Attempt
+ $status =fwrite ($bf,start_tag("ATTEMPT",5,true));
+ //Print attempt contents
+ fwrite ($bf,full_tag("USERID",6,false,$attempt->userid));
+ fwrite ($bf,full_tag("CORRECT",6,false,$attempt->correct));
+ fwrite ($bf,full_tag("TIMESEEN",6,false,$attempt->timeseen));
+ fwrite ($bf,full_tag("RETRY",6,false,$attempt->retry));
+ //End attempt
+ $status =fwrite ($bf,end_tag("ATTEMPT",5,true));
+ }
+ //Write end tag
+ $status =fwrite ($bf,end_tag("ATTEMPTS",4,true));
+ }
+ return $status;
+ }
+
+
+ //Backup lesson_grades contents (executed from backup_lesson_mods)
+ function backup_lesson_grades ($bf,$preferences,$lessonid) {
+
+ global $CFG;
+
+ $status = true;
+
+ $grades = get_records("lesson_grades", "lessonid", $lessonid);
+
+ //If there is grades
+ if ($grades) {
+ //Write start tag
+ $status =fwrite ($bf,start_tag("GRADES",8,true));
+ //Iterate over each grade
+ foreach ($grades as $grade) {
+ //Start grade
+ $status =fwrite ($bf,start_tag("GRADE",9,true));
+ //Print grade contents
+ fwrite ($bf,full_tag("USERID",10,false,$grade->userid));
+ fwrite ($bf,full_tag("GRADE_VALUE",10,false,$grade->grade));
+ fwrite ($bf,full_tag("LATE",10,false,$grade->late));
+ fwrite ($bf,full_tag("COMPLETED",10,false,$grade->completed));
+ //End comment
+ $status =fwrite ($bf,end_tag("GRADE",9,true));
+ }
+ //Write end tag
+ $status =fwrite ($bf,end_tag("GRADES",8,true));
+ }
+ return $status;
+ }
+ //Return an array of info (name,value)
+ function lesson_check_backup_mods($course,$user_data=false,$backup_unique_code) {
+ //First the course data
+ $info[0][0] = get_string("modulenameplural","lesson");
+ if ($ids = lesson_ids($course)) {
+ $info[0][1] = count($ids);
+ } else {
+ $info[0][1] = 0;
+ }
+
+ //Now, if requested, the user_data
+ if ($user_data) {
+ $info[1][0] = get_string("attempts","lesson");
+ if ($ids = lesson_attempts_ids_by_course ($course)) {
+ $info[1][1] = count($ids);
+ } else {
+ $info[1][1] = 0;
+ }
+ }
+ return $info;
+ }
+
+
+
+ // INTERNAL FUNCTIONS. BASED IN THE MOD STRUCTURE
+
+ //Returns an array of lesson id
+ function lesson_ids ($course) {
+
+ global $CFG;
+
+ return get_records_sql ("SELECT l.id, l.course
+ FROM {$CFG->prefix}lesson l
+ WHERE l.course = '$course'");
+ }
+
+ //Returns an array of lesson_submissions id
+ function lesson_attempts_ids_by_course ($course) {
+
+ global $CFG;
+
+ return get_records_sql ("SELECT a.id , a.lessonid
+ FROM {$CFG->prefix}lesson_attempts a,
+ {$CFG->prefix}lesson l
+ WHERE l.course = '$course' AND
+ a.lessonid = l.id");
+ }
+?>
diff --git a/mod/lesson/db/mysql.php b/mod/lesson/db/mysql.php
new file mode 100644
index 00000000000..b3bfa4dd348
--- /dev/null
+++ b/mod/lesson/db/mysql.php
@@ -0,0 +1,18 @@
+
diff --git a/mod/lesson/db/mysql.sql b/mod/lesson/db/mysql.sql
new file mode 100644
index 00000000000..4561319b6af
--- /dev/null
+++ b/mod/lesson/db/mysql.sql
@@ -0,0 +1,72 @@
+# This file contains a complete database schema for all the
+# tables used by the mlesson module, written in SQL
+
+# It may also contain INSERT statements for particular data
+# that may be used, especially new entries in the table log_display
+
+CREATE TABLE `prefix_lesson` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `course` int(10) unsigned NOT NULL default '0',
+ `name` varchar(255) NOT NULL default '',
+ `grade` tinyint(3) NOT NULL default '0',
+ `maxanswers` int(3) unsigned NOT NULL default '4',
+ `retake` int(3) unsigned NOT NULL default '1',
+ `available` int(10) unsigned NOT NULL default '0',
+ `deadline` int(10) unsigned NOT NULL default '0',
+ `timemodified` int(10) unsigned NOT NULL default '0',
+ PRIMARY KEY (`id`)
+) COMMENT='Defines lesson';
+# --------------------------------------------------------
+
+CREATE TABLE `prefix_lesson_pages` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `lessonid` int(10) unsigned NOT NULL default '0',
+ `prevpageid` int(10) unsigned NOT NULL default '0',
+ `nextpageid` int(10) unsigned NOT NULL default '0',
+ `timecreated` int(10) unsigned NOT NULL default '0',
+ `timemodified` int(10) unsigned NOT NULL default '0',
+ `title` varchar(255) NOT NULL default '',
+ `contents` text NOT NULL default '',
+ PRIMARY KEY (`id`)
+) COMMENT='Defines lesson_pages';
+# --------------------------------------------------------
+
+CREATE TABLE `prefix_lesson_answers` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `lessonid` int(10) unsigned NOT NULL default '0',
+ `pageid` int(10) unsigned NOT NULL default '0',
+ `jumpto` int(11) NOT NULL default '0',
+ `timecreated` int(10) unsigned NOT NULL default '0',
+ `timemodified` int(10) unsigned NOT NULL default '0',
+ `answer` text NOT NULL default '',
+ `response` text NOT NULL default '',
+ PRIMARY KEY (`id`)
+) COMMENT='Defines lesson_answers';
+# --------------------------------------------------------
+
+CREATE TABLE `prefix_lesson_attempts` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `lessonid` int(10) unsigned NOT NULL default '0',
+ `pageid` int(10) unsigned NOT NULL default '0',
+ `userid` int(10) unsigned NOT NULL default '0',
+ `answerid` int(10) unsigned NOT NULL default '0',
+ `retry` int(3) unsigned NOT NULL default '0',
+ `correct` int(10) unsigned NOT NULL default '0',
+ `timeseen` int(10) unsigned NOT NULL default '0',
+ PRIMARY KEY (`id`)
+) COMMENT='Defines lesson_attempts';
+# --------------------------------------------------------
+
+CREATE TABLE `prefix_lesson_grades` (
+ `id` int(10) unsigned NOT NULL auto_increment,
+ `lessonid` int(10) unsigned NOT NULL default '0',
+ `userid` int(10) unsigned NOT NULL default '0',
+ `grade` int(3) unsigned NOT NULL default '0',
+ `late` int(3) unsigned NOT NULL default '0',
+ `completed` int(10) unsigned NOT NULL default '0',
+ PRIMARY KEY (`id`)
+) COMMENT='Defines lesson_grades';
+# --------------------------------------------------------
+
+
+
diff --git a/mod/lesson/icon.gif b/mod/lesson/icon.gif
new file mode 100755
index 00000000000..550df5db8c4
Binary files /dev/null and b/mod/lesson/icon.gif differ
diff --git a/mod/lesson/index.php b/mod/lesson/index.php
new file mode 100644
index 00000000000..f062d11f2a3
--- /dev/null
+++ b/mod/lesson/index.php
@@ -0,0 +1,105 @@
+id);
+
+ add_to_log($course->id, "lesson", "view all", "index.php?id=$course->id", "");
+
+
+/// Get all required strings
+
+ $strlessons = get_string("modulenameplural", "lesson");
+ $strlesson = get_string("modulename", "lesson");
+
+
+/// Print the header
+
+ if ($course->category) {
+ $navigation = "id\">$course->shortname ->";
+ }
+
+ print_header("$course->shortname: $strlessons", "$course->fullname", "$navigation $strlessons", "", "", true, "", navmenu($course));
+
+/// Get all the appropriate data
+
+ if (! $lessons = get_all_instances_in_course("lesson", $course)) {
+ notice("There are no lessons", "../../course/view.php?id=$course->id");
+ die;
+ }
+
+/// Print the list of instances (your module will probably extend this)
+
+ $timenow = time();
+ $strname = get_string("name");
+ $strgrade = get_string("grade");
+ $strdeadline = get_string("deadline", "lesson");
+ $strweek = get_string("week");
+ $strtopic = get_string("topic");
+
+ if ($course->format == "weeks") {
+ $table->head = array ($strweek, $strname, $strgrade, $strdeadline);
+ $table->align = array ("CENTER", "LEFT", "CENTER", "CENTER");
+ } else if ($course->format == "topics") {
+ $table->head = array ($strtopic, $strname);
+ $table->align = array ("CENTER", "LEFT", "CENTER", "CENTER");
+ } else {
+ $table->head = array ($strname);
+ $table->align = array ("LEFT", "CENTER", "CENTER");
+ }
+
+ foreach ($lessons as $lesson) {
+ if (!$lesson->visible) {
+ //Show dimmed if the mod is hidden
+ $link = "coursemodule\">$lesson->name";
+ } else {
+ //Show normal if the mod is visible
+ $link = "coursemodule\">$lesson->name";
+ }
+
+ if ($lesson->deadline > $timenow) {
+ $due = userdate($lesson->deadline);
+ } else {
+ $due = "".userdate($lesson->deadline)."";
+ }
+
+ if ($course->format == "weeks" or $course->format == "topics") {
+ if (isteacher($course->id)) {
+ $grade_value = $lesson->grade;
+ } else {
+ // it's a student, show their maximum grade
+ if ($grades = get_records_select("lesson_grades", "lessonid = $lesson->id AND
+ userid = $USER->id", "grade DESC")) {
+ foreach ($grades as $grade) {
+ // grades are stored as percentages
+ $grade_value = number_format($grade->grade * $lesson->grade / 100, 1);
+ break; // only the first (largest) grade needed
+ }
+ } else {
+ $grade_value = 0;
+ }
+ }
+ $table->data[] = array ($lesson->section, $link, $grade_value, $due);
+ } else {
+ $table->data[] = array ($link, $grade_value, $due);
+ }
+ }
+
+ echo " ";
+
+ print_table($table);
+
+/// Finish the page
+
+ print_footer($course);
+
+?>
diff --git a/mod/lesson/lesson.php b/mod/lesson/lesson.php
new file mode 100644
index 00000000000..46540260457
--- /dev/null
+++ b/mod/lesson/lesson.php
@@ -0,0 +1,669 @@
+course)) {
+ error("Course is misconfigured");
+ }
+
+ if (! $lesson = get_record("lesson", "id", $cm->instance)) {
+ error("Course module is incorrect");
+ }
+
+ require_login($course->id);
+
+ // set up some general variables
+ $usehtmleditor = can_use_html_editor();
+ echo "\$usehtmleditor:$usehtmleditor";
+
+ $navigation = "";
+ if ($course->category) {
+ $navigation = "id\">$course->shortname ->";
+ }
+
+ $strlessons = get_string("modulenameplural", "lesson");
+ $strlesson = get_string("modulename", "lesson");
+ $strlessonname = $lesson->name;
+
+ // ... print the header and...
+ print_header("$course->shortname: $lesson->name", "$course->fullname",
+ "$navigation id>$strlessons ->
+ id\">$lesson->name -> $action",
+ "", "", true);
+
+ //...get the action
+ require_variable($action);
+
+
+ /************** add page ************************************/
+ if ($action == 'addpage' ) {
+
+ if (!isteacher($course->id)) {
+ error("Only teachers can look at this page");
+ }
+
+ // first get the preceeding page
+ $pageid = $_GET['pageid'];
+
+ // set of jump array
+ $jump[0] = get_string("thispage", "lesson");
+ $jump[NEXTPAGE] = get_string("nextpage", "lesson");
+ $jump[EOL] = get_string("endoflesson", "lesson");
+ if (!$apageid = get_field("lesson_pages", "id", "lessonid", $lesson->id, "prevpageid", 0)) {
+ error("Add page: first page not found");
+ }
+ while (true) {
+ if ($apageid) {
+ $title = get_field("lesson_pages", "title", "id", $apageid);
+ $jump[$apageid] = $title;
+ $apageid = get_field("lesson_pages", "nextpageid", "id", $apageid);
+ } else {
+ // last page reached
+ break;
+ }
+ }
+
+ // give teacher a blank proforma
+ print_heading_with_help(get_string("addanewpage", "lesson"), "overview", "lesson");
+ ?>
+
+ id)) {
+ error("Only teachers can look at this page");
+ }
+
+ if (empty($_GET['pageid'])) {
+ error("Confirm delete: pageid missing");
+ }
+ $pageid = $_GET['pageid'];
+ if (!$thispage = get_record("lesson_pages", "id", $pageid)) {
+ error("Confirm delete: the page record not found");
+ }
+ print_heading(get_string("deletingpage", "lesson", $thispage->title));
+ // print the jumps to this page
+ if ($answers = get_records_select("lesson_answers", "lessonid = $lesson->id AND jumpto = $pageid + 1")) {
+ print_heading(get_string("thefollowingpagesjumptothispage", "lesson"));
+ echo "
\n";
+ foreach ($answers as $answer) {
+ if (!$title = get_field("lesson_pages", "title", "id", $answer->pageid)) {
+ error("Confirm delete: page title not found");
+ }
+ echo $title." \n";
+ }
+ }
+ notice_yesno(get_string("confirmdeletionofthispage","lesson"),
+ "lesson.php?action=delete&id=$cm->id&pageid=$pageid]",
+ "view.php?id=$cm->id");
+ }
+
+
+ /****************** continue ************************************/
+ elseif ($action == 'continue' ) {
+ // record answer (if necessary) and show response (if any)
+
+ if (empty($_POST['pageid'])) {
+ error("Continue: pageid missing");
+ }
+ $pageid = $_POST['pageid'];
+ // get the answer
+ if (empty($_POST['answerid'])) {
+ print_heading(get_string("noanswer", "lesson"));
+ redirect("view.php?id=$cm->id&action=navigation&pageid=$pageid",
+ get_string("continue", "lesson"));
+ } else {
+ $answerid = $_POST['answerid'];
+ if (!$answer = get_record("lesson_answers", "id", $answerid)) {
+ error("Continue: answer record not found");
+ }
+ $ntries = count_records("lesson_grades", "lessonid", $lesson->id, "userid", $USER->id);
+ if (isstudent($course->id)) {
+ // record student's attempt
+ $correct = get_field("lesson_answers", "correct", "id", $answerid);
+ $attempt->lessonid = $lesson->id;
+ $attempt->pageid = $pageid;
+ $attempt->userid = $USER->id;
+ $attempt->answerid = $answerid;
+ $attempt->retry = $ntries;
+ $attempt->correct = lesson_iscorrect($pageid, $answer->jumpto);
+ $attempt->timeseen = time();
+ if (!$newattemptid = insert_record("lesson_attempts", $attempt)) {
+ error("Continue: attempt not inserted");
+ }
+ }
+
+ // convert jumpto to a proper page id
+ if ($answer->jumpto == 0) {
+ $newpageid = $pageid;
+ } elseif ($answer->jumpto == NEXTPAGE) {
+ if (!$newpageid = get_field("lesson_pages", "nextpageid", "id", $pageid)) {
+ // no nextpage go to end of lesson
+ $newpageid = EOL;
+ }
+ } else {
+ $newpageid = $answer->jumpto;
+ }
+
+ // display response (if there is one)
+ if ($answer->response) {
+ $title = get_field("lesson_pages", "title", "id", $pageid);
+ print_heading($title);
+ echo "
\n";
+ }
+ if ($page->nextpageid) {
+ if (!$page = get_record("lesson_pages", "id", $page->nextpageid)) {
+ error("Teacher view: Next page not found!");
+ }
+ } else {
+ // last page reached
+ break;
+ }
+ }
+ echo "
\n";
+ }
+
+
+ /****************** moveit ************************************/
+ elseif ($action == 'moveit') {
+
+ if (!isteacher($course->id)) {
+ error("Only teachers can look at this page");
+ }
+
+ $pageid = $_GET['pageid']; // page to move
+ if (!$page = get_record("lesson_pages", "id", $pageid)) {
+ error("Moveit: page not found");
+ }
+ $after = $_GET['after']; // target page
+
+ print_heading(get_string("moving", "lesson", $page->title));
+
+ // first step. determine the new first page
+ // (this is done first as the current first page will be lost in the next step)
+ if (!$after) {
+ // the moved page is the new first page
+ $newfirstpageid = $pageid;
+ // reset $after so that is points to the last page
+ // (when the pages are in a ring this will in effect be the first page)
+ if ($page->nextpageid) {
+ if (!$after = get_field("lesson_pages", "id", "lessonid", $lesson->id, "nextpageid", 0)) {
+ error("Moveit: last page id not found");
+ }
+ } else {
+ // the page being moved is the last page, so the new last page will be
+ $after = $page->prevpageid;
+ }
+ } elseif (!$page->prevpageid) {
+ // the page to be moved was the first page, so the following page must be the new first page
+ $newfirstpageid = $page->nextpageid;
+ } else {
+ // the current first page remains the first page
+ if (!$newfirstpageid = get_field("lesson_pages", "id", "lessonid", $lesson->id, "prevpageid", 0)) {
+ error("Moveit: current first page id not found");
+ }
+ }
+ // the rest is all unconditional...
+
+ // second step. join pages into a ring
+ if (!$firstpageid = get_field("lesson_pages", "id", "lessonid", $lesson->id, "prevpageid", 0)) {
+ error("Moveit: firstpageid not found");
+ }
+ if (!$lastpageid = get_field("lesson_pages", "id", "lessonid", $lesson->id, "nextpageid", 0)) {
+ error("Moveit: lastpage not found");
+ }
+ if (!set_field("lesson_pages", "prevpageid", $lastpageid, "id", $firstpageid)) {
+ error("Moveit: unable to update link");
+ }
+ if (!set_field("lesson_pages", "nextpageid", $firstpageid, "id", $lastpageid)) {
+ error("Moveit: unable to update link");
+ }
+
+ echo "
\$newfirstpageid: $newfirstpageid";
+ echo "
\$after: $after";
+
+ // third step. remove the page to be moved
+ if (!$prevpageid = get_field("lesson_pages", "prevpageid", "id", $pageid)) {
+ error("Moveit: prevpageid not found");
+ }
+ if (!$nextpageid = get_field("lesson_pages", "nextpageid", "id", $pageid)) {
+ error("Moveit: nextpageid not found");
+ }
+ if (!set_field("lesson_pages", "nextpageid", $nextpageid, "id", $prevpageid)) {
+ error("Moveit: unable to update link");
+ }
+ if (!set_field("lesson_pages", "prevpageid", $prevpageid, "id", $nextpageid)) {
+ error("Moveit: unable to update link");
+ }
+
+ // fourth step. insert page to be moved in new place...
+ if (!$nextpageid = get_field("lesson_pages", "nextpageid", "id", $after)) {
+ error("Movit: nextpageid not found");
+ }
+ if (!set_field("lesson_pages", "nextpageid", $pageid, "id", $after)) {
+ error("Moveit: unable to update link");
+ }
+ if (!set_field("lesson_pages", "prevpageid", $pageid, "id", $nextpageid)) {
+ error("Moveit: unable to update link");
+ }
+ // ...and set the links in the moved page
+ if (!set_field("lesson_pages", "prevpageid", $after, "id", $pageid)) {
+ error("Moveit: unable to update link");
+ }
+ if (!set_field("lesson_pages", "nextpageid", $nextpageid, "id", $pageid)) {
+ error("Moveit: unable to update link");
+ }
+
+ // fifth step. break the ring
+ if (!$newlastpageid = get_field("lesson_pages", "prevpageid", "id", $newfirstpageid)) {
+ error("Moveit: newlastpageid not found");
+ }
+ if (!set_field("lesson_pages", "prevpageid", 0, "id", $newfirstpageid)) {
+ error("Moveit: unable to update link");
+ }
+ if (!set_field("lesson_pages", "nextpageid", 0, "id", $newlastpageid)) {
+ error("Moveit: unable to update link");
+ }
+ }
+
+
+ /****************** update page ************************************/
+ elseif ($action == 'updatepage' ) {
+
+ if (!isteacher($course->id)) {
+ error("Only teachers can look at this page");
+ }
+
+ $timenow = time();
+ $form = (object) $HTTP_POST_VARS;
+
+ $page->id = $form->pageid;
+ $page->timemodified = $timenow;
+ $page->title = $form->title;
+ $page->contents = trim($form->contents);
+ if (!update_record("lesson_pages", $page)) {
+ error("Update page: page not updated");
+ }
+ for ($i = 0; $i < $lesson->maxanswers; $i++) {
+ if (trim(strip_tags($form->answer[$i]))) { // strip_tags because the HTML gives
...
+ if ($form->answerid[$i]) {
+ $oldanswer->id = $form->answerid[$i];
+ $oldanswer->timemodified = $timenow;
+ $oldanswer->answer = trim($form->answer[$i]);
+ $oldanswer->response = trim($form->response[$i]);
+ $oldanswer->jumpto = $form->jumpto[$i];
+ if (!update_record("lesson_answers", $oldanswer)) {
+ error("Update page: answer $i not updated");
+ }
+ } else {
+ // it's a new answer
+ $newanswer->lessonid = $lesson->id;
+ $newanswer->pageid = $page->id;
+ $newanswer->timecreated = $timenow;
+ $newanswer->answer = trim($form->answer[$i]);
+ $newanswer->response = trim($form->response[$i]);
+ $newanswer->jumpto = $form->jumpto[$i];
+ $newanswerid = insert_record("lesson_answers", $newanswer);
+ if (!$newanswerid) {
+ error("Update page: answer record not inserted");
+ }
+ }
+ } else {
+ if ($form->answerid[$i]) {
+ // need to delete blanked out answer
+ if (!delete_records("lesson_answers", "id", $form->answerid[$i])) {
+ error("Update page: unable to delete answer record");
+ }
+ }
+ }
+ }
+ redirect("view.php?id=$cm->id", get_string("ok"));
+ }
+
+
+ /*************** no man's land **************************************/
+ else {
+ error("Fatal Error: Unknown Action: ".$action."\n");
+ }
+
+ print_footer($course);
+
+?>
+
diff --git a/mod/lesson/lib.php b/mod/lesson/lib.php
new file mode 100644
index 00000000000..d4800d348cd
--- /dev/null
+++ b/mod/lesson/lib.php
@@ -0,0 +1,316 @@
+\n";
+ if ($nothing) {
+ $output .= "