Merge branch 'MDL-28044' of git://github.com/nebgor/moodle
authorEloy Lafuente (stronk7) <stronk7@moodle.org>
Wed, 29 Jun 2011 23:59:49 +0000 (01:59 +0200)
committerEloy Lafuente (stronk7) <stronk7@moodle.org>
Wed, 29 Jun 2011 23:59:49 +0000 (01:59 +0200)
113 files changed:
backup/moodle2/restore_stepslib.php
blocks/calendar_month/block_calendar_month.php
blocks/calendar_upcoming/block_calendar_upcoming.php
blog/lib.php
calendar/event.php
calendar/export.php
calendar/lib.php
calendar/preferences.php
calendar/renderer.php
calendar/set.php
calendar/view.php
course/lib.php
course/report/completion/lang/en/coursereport_completion.php
course/report/completion/lib.php
course/report/lib.php [new file with mode: 0644]
course/report/log/lang/en/coursereport_log.php
course/report/log/lib.php
course/report/outline/index.php
course/report/outline/lang/en/coursereport_outline.php
course/report/outline/lib.php
course/report/participation/lang/en/coursereport_participation.php
course/report/participation/lib.php
course/report/progress/lang/en/coursereport_progress.php
course/report/progress/lib.php
course/report/stats/lang/en/coursereport_stats.php
course/report/stats/lib.php
lang/en/mathslib.php [new file with mode: 0644]
lang/en/pagetype.php
lib/adminlib.php
lib/blocklib.php
lib/db/services.php
lib/db/upgrade.php
lib/evalmath/evalmath.class.php
lib/evalmath/readme_moodle.txt
lib/messagelib.php
lib/moodlelib.php
lib/navigationlib.php
lib/outputrenderers.php
lib/pagelib.php
lib/questionlib.php
lib/simpletest/testmathslib.php
local/qeupgradehelper/locallib.php
message/externallib.php
message/lib.php
mod/assignment/lang/en/assignment.php
mod/assignment/lib.php
mod/chat/lib.php
mod/choice/lib.php
mod/data/export_form.php
mod/data/lib.php
mod/feedback/item/multichoice/lib.php
mod/feedback/item/multichoicerated/lib.php
mod/feedback/lib.php
mod/folder/lib.php
mod/forum/lib.php
mod/glossary/lib.php
mod/imscp/lib.php
mod/lesson/continue.php
mod/lesson/format.php
mod/lesson/import.php
mod/lesson/import_form.php
mod/lesson/lang/en/lesson.php
mod/lesson/lib.php
mod/lesson/locallib.php
mod/lesson/pagetypes/essay.php
mod/lesson/pagetypes/matching.php
mod/lesson/pagetypes/multichoice.php
mod/lesson/pagetypes/shortanswer.php
mod/lesson/pagetypes/truefalse.php
mod/lesson/styles.css
mod/lesson/view.php
mod/page/lib.php
mod/quiz/backup/moodle2/restore_quiz_stepslib.php
mod/quiz/db/upgrade.php
mod/quiz/db/upgradelib.php
mod/quiz/lib.php
mod/quiz/locallib.php
mod/resource/lib.php
mod/scorm/lib.php
mod/scorm/locallib.php
mod/survey/lib.php
mod/url/lib.php
mod/wiki/lib.php
mod/workshop/lib.php
notes/lib.php
pluginfile.php
question/behaviour/deferredcbm/lang/en/qbehaviour_deferredcbm.php
question/editlib.php
question/engine/upgrade/behaviourconverters.php
question/preview.php
question/previewlib.php
question/type/calculated/db/simpletest/testupgradelibnewqe.php
question/type/calculated/db/upgradelib.php
question/type/calculated/question.php
question/type/calculatedmulti/db/simpletest/testupgradelibnewqe.php
question/type/calculatedmulti/db/upgradelib.php
question/type/calculatedsimple/db/simpletest/testupgradelibnewqe.php
question/type/multianswer/db/simpletest/testupgradelibnewqe.php
question/type/multianswer/renderer.php
question/type/numerical/edit_numerical_form.php
question/type/numerical/lang/en/qtype_numerical.php
question/type/numerical/question.php
question/type/numerical/questiontype.php
question/type/numerical/renderer.php
question/type/numerical/simpletest/testanswerprocessor.php
question/type/numerical/simpletest/testform.php [new file with mode: 0755]
question/type/numerical/simpletest/testquestion.php
question/type/truefalse/db/simpletest/testupgradelibnewqe.php
question/type/truefalse/version.php
tag/lib.php
user/externallib.php
user/lib.php
version.php

index 6178a04..26f33c0 100644 (file)
@@ -273,7 +273,9 @@ class restore_gradebook_structure_step extends restore_structure_step {
         //$this->set_mapping('grade_setting', $oldid, $newitemid);
     }
 
-    //put all activity grade items in the correct grade category and mark all for recalculation
+    /**
+     * put all activity grade items in the correct grade category and mark all for recalculation
+     */
     protected function after_execute() {
         global $DB;
 
@@ -284,8 +286,15 @@ class restore_gradebook_structure_step extends restore_structure_step {
         );
         $rs = $DB->get_recordset('backup_ids_temp', $conditions);
 
+        // We need this for calculation magic later on.
+        $mappings = array();
+
         if (!empty($rs)) {
             foreach($rs as $grade_item_backup) {
+
+                // Store the oldid with the new id.
+                $mappings[$grade_item_backup->itemid] = $grade_item_backup->newitemid;
+
                 $updateobj = new stdclass();
                 $updateobj->id = $grade_item_backup->newitemid;
 
@@ -301,6 +310,55 @@ class restore_gradebook_structure_step extends restore_structure_step {
         }
         $rs->close();
 
+        // We need to update the calculations for calculated grade items that may reference old
+        // grade item ids using ##gi\d+##.
+        list($sql, $params) = $DB->get_in_or_equal(array_values($mappings), SQL_PARAMS_NAMED);
+        $sql = "SELECT gi.id, gi.calculation
+                  FROM {grade_items} gi
+                 WHERE gi.id {$sql} AND
+                       calculation IS NOT NULL";
+        $rs = $DB->get_recordset_sql($sql, $params);
+        foreach ($rs as $gradeitem) {
+            // Collect all of the used grade item id references
+            if (preg_match_all('/##gi(\d+)##/', $gradeitem->calculation, $matches) < 1) {
+                // This calculation doesn't reference any other grade items... EASY!
+                continue;
+            }
+            // For this next bit we are going to do the replacement of id's in two steps:
+            // 1. We will replace all old id references with a special mapping reference.
+            // 2. We will replace all mapping references with id's
+            // Why do we do this?
+            // Because there potentially there will be an overlap of ids within the query and we
+            // we substitute the wrong id.. safest way around this is the two step system
+            $calculationmap = array();
+            $mapcount = 0;
+            foreach ($matches[1] as $match) {
+                // Check that the old id is known to us, if not it was broken to begin with and will
+                // continue to be broken.
+                if (!array_key_exists($match, $mappings)) {
+                    continue;
+                }
+                // Our special mapping key
+                $mapping = '##MAPPING'.$mapcount.'##';
+                // The old id that exists within the calculation now
+                $oldid = '##gi'.$match.'##';
+                // The new id that we want to replace the old one with.
+                $newid = '##gi'.$mappings[$match].'##';
+                // Replace in the special mapping key
+                $gradeitem->calculation = str_replace($oldid, $mapping, $gradeitem->calculation);
+                // And record the mapping
+                $calculationmap[$mapping] = $newid;
+                $mapcount++;
+            }
+            // Iterate all special mappings for this calculation and replace in the new id's
+            foreach ($calculationmap as $mapping => $newid) {
+                $gradeitem->calculation = str_replace($mapping, $newid, $gradeitem->calculation);
+            }
+            // Update the calculation now that its being remapped
+            $DB->update_record('grade_items', $gradeitem);
+        }
+        $rs->close();
+
         //need to correct the grade category path and parent
         $conditions = array(
             'courseid' => $this->get_courseid()
@@ -1800,28 +1858,47 @@ class restore_activity_grades_structure_step extends restore_structure_step {
     }
 
     protected function process_grade_item($data) {
+        global $DB;
 
         $data = (object)($data);
         $oldid       = $data->id;        // We'll need these later
         $oldparentid = $data->categoryid;
+        $courseid = $this->get_courseid();
 
         // make sure top course category exists, all grade items will be associated
         // to it. Later, if restoring the whole gradebook, categories will be introduced
-        $coursecat = grade_category::fetch_course_category($this->get_courseid());
+        $coursecat = grade_category::fetch_course_category($courseid);
         $coursecatid = $coursecat->id; // Get the categoryid to be used
 
+        $idnumber = null;
+        if (!empty($data->idnumber)) {
+            // Don't get any idnumber from course module. Keep them as they are in grade_item->idnumber
+            // Reason: it's not clear what happens with outcomes->idnumber or activities with multiple items (workshop)
+            // so the best is to keep the ones already in the gradebook
+            // Potential problem: duplicates if same items are restored more than once. :-(
+            // This needs to be fixed in some way (outcomes & activities with multiple items)
+            // $data->idnumber     = get_coursemodule_from_instance($data->itemmodule, $data->iteminstance)->idnumber;
+            // In any case, verify always for uniqueness
+            $sql = "SELECT cm.id
+                      FROM {course_modules} cm
+                     WHERE cm.course = :courseid AND
+                           cm.idnumber = :idnumber AND
+                           cm.id <> :cmid";
+            $params = array(
+                'courseid' => $courseid,
+                'idnumber' => $data->idnumber,
+                'cmid' => $this->task->get_moduleid()
+            );
+            if (!$DB->record_exists_sql($sql, $params) && !$DB->record_exists('grade_items', array('courseid' => $courseid, 'idnumber' => $data->idnumber))) {
+                $idnumber = $data->idnumber;
+            }
+        }
+
         unset($data->id);
         $data->categoryid   = $coursecatid;
         $data->courseid     = $this->get_courseid();
         $data->iteminstance = $this->task->get_activityid();
-        // Don't get any idnumber from course module. Keep them as they are in grade_item->idnumber
-        // Reason: it's not clear what happens with outcomes->idnumber or activities with multiple items (workshop)
-        // so the best is to keep the ones already in the gradebook
-        // Potential problem: duplicates if same items are restored more than once. :-(
-        // This needs to be fixed in some way (outcomes & activities with multiple items)
-        // $data->idnumber     = get_coursemodule_from_instance($data->itemmodule, $data->iteminstance)->idnumber;
-        // In any case, verify always for uniqueness
-        $data->idnumber = grade_verify_idnumber($data->idnumber, $this->get_courseid()) ? $data->idnumber : null;
+        $data->idnumber     = $idnumber;
         $data->scaleid      = $this->get_mappingid('scale', $data->scaleid);
         $data->outcomeid    = $this->get_mappingid('outcome', $data->outcomeid);
         $data->timecreated  = $this->apply_date_offset($data->timecreated);
@@ -2827,8 +2904,7 @@ abstract class restore_questions_activity_structure_step extends restore_activit
         $usage->preferredbehaviour = $quiz->preferredbehaviour;
         $usage->id = $DB->insert_record('question_usages', $usage);
 
-        $DB->set_field('quiz_attempts', 'uniqueid', $usage->id,
-                array('id' => $this->get_mappingid('quiz_attempt', $data->id)));
+        $this->inform_new_usage_id($usage->id);
 
         $data->uniqueid = $usage->id;
         $upgrader->save_usage($quiz->preferredbehaviour, $data, $qas, $quiz->questions);
@@ -2846,10 +2922,15 @@ abstract class restore_questions_activity_structure_step extends restore_activit
         $qstates = array();
         foreach ($data->states['state'] as $state) {
             if ($state['question'] == $questionid) {
-                $qstates[$state['seq_number']] = (object) $state;
+                // It would be natural to use $state['seq_number'] as the array-key
+                // here, but it seems that buggy behaviour in 2.0 and early can
+                // mean that that is not unique, so we use id, which is guaranteed
+                // to be unique.
+                $qstates[$state['id']] = (object) $state;
             }
         }
         ksort($qstates);
+        $qstates = array_values($qstates);
 
         return array($qsession, $qstates);
     }
index 9fa7ecb..b578d4d 100644 (file)
@@ -19,8 +19,6 @@ class block_calendar_month extends block_base {
         if ($this->content !== NULL) {
             return $this->content;
         }
-        // Reset the session variables
-        calendar_session_vars($this->page->course);
 
         $this->content = new stdClass;
         $this->content->text = '';
@@ -29,52 +27,30 @@ class block_calendar_month extends block_base {
         // [pj] To me it looks like this if would never be needed, but Penny added it
         // when committing the /my/ stuff. Reminder to discuss and learn what it's about.
         // It definitely needs SOME comment here!
-        $courseshown = $this->page->course->id;
+        $courseid = $this->page->course->id;
+        $issite = ($courseid == SITEID);
 
-        if ($courseshown == SITEID) {
+        if ($issite) {
             // Being displayed at site level. This will cause the filter to fall back to auto-detecting
             // the list of courses it will be grabbing events from.
-            $filtercourse    = NULL;
-            $groupeventsfrom = NULL;
-            $SESSION->cal_courses_shown = calendar_get_default_courses(true);
-            calendar_set_referring_course(0);
-
+            $filtercourse = calendar_get_default_courses();
         } else {
             // Forcibly filter events to include only those from the particular course we are in.
-            $filtercourse    = array($courseshown => $this->page->course);
-            $groupeventsfrom = array($courseshown => 1);
-        }
-
-        // We 'll need this later
-        calendar_set_referring_course($courseshown);
-
-        // MDL-9059, set to show this course when admins go into a course, then unset it.
-        if ($this->page->course->id != SITEID && !isset($SESSION->cal_courses_shown[$this->page->course->id]) && has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_SYSTEM))) {
-            $courseset = true;
-            $SESSION->cal_courses_shown[$this->page->course->id] = $this->page->course;
+            $filtercourse = array($courseid => $this->page->course);
         }
 
-        // Be VERY careful with the format for default courses arguments!
-        // Correct formatting is [courseid] => 1 to be concise with moodlelib.php functions.
-        calendar_set_filters($courses, $group, $user, $filtercourse, $groupeventsfrom, false);
-        if ($courseshown == SITEID) {
+        list($courses, $group, $user) = calendar_set_filters($filtercourse);
+        if ($issite) {
             // For the front page
-            $this->content->text .= calendar_top_controls('frontpage', array('id' => $courseshown, 'm' => $cal_m, 'y' => $cal_y));
+            $this->content->text .= calendar_top_controls('frontpage', array('id' => $courseid, 'm' => $cal_m, 'y' => $cal_y));
             $this->content->text .= calendar_get_mini($courses, $group, $user, $cal_m, $cal_y);
             // No filters for now
-
         } else {
             // For any other course
-            $this->content->text .= calendar_top_controls('course', array('id' => $courseshown, 'm' => $cal_m, 'y' => $cal_y));
+            $this->content->text .= calendar_top_controls('course', array('id' => $courseid, 'm' => $cal_m, 'y' => $cal_y));
             $this->content->text .= calendar_get_mini($courses, $group, $user, $cal_m, $cal_y);
             $this->content->text .= '<h3 class="eventskey">'.get_string('eventskey', 'calendar').'</h3>';
-            $this->content->text .= '<div class="filters">'.calendar_filter_controls('course', '', $this->page->course).'</div>';
-
-        }
-
-        // MDL-9059, unset this so that it doesn't stay in session
-        if (!empty($courseset)) {
-            unset($SESSION->cal_courses_shown[$this->page->course->id]);
+            $this->content->text .= '<div class="filters">'.calendar_filter_controls($this->page->url).'</div>';
         }
 
         return $this->content;
index 21d63b4..3b35210 100644 (file)
@@ -15,14 +15,12 @@ class block_calendar_upcoming extends block_base {
         if ($this->content !== NULL) {
             return $this->content;
         }
-        // Reset the session variables
-        calendar_session_vars($this->page->course);
         $this->content = new stdClass;
         $this->content->text = '';
 
+        $filtercourse    = array();
         if (empty($this->instance)) { // Overrides: use no course at all
             $courseshown = false;
-            $filtercourse = array();
             $this->content->footer = '';
 
         } else {
@@ -31,8 +29,7 @@ class block_calendar_upcoming extends block_base {
                                      '/calendar/view.php?view=upcoming&amp;course='.$courseshown.'">'.
                                       get_string('gotocalendar', 'calendar').'</a>...</div>';
             $context = get_context_instance(CONTEXT_COURSE, $courseshown);
-            if (has_capability('moodle/calendar:manageentries', $context) ||
-                has_capability('moodle/calendar:manageownentries', $context)) {
+            if (has_any_capability(array('moodle/calendar:manageentries', 'moodle/calendar:manageownentries'), $context)) {
                 $this->content->footer .= '<div class="newevent"><a href="'.$CFG->wwwroot.
                                           '/calendar/event.php?action=new&amp;course='.$courseshown.'">'.
                                            get_string('newevent', 'calendar').'</a>...</div>';
@@ -40,36 +37,34 @@ class block_calendar_upcoming extends block_base {
             if ($courseshown == SITEID) {
                 // Being displayed at site level. This will cause the filter to fall back to auto-detecting
                 // the list of courses it will be grabbing events from.
-                $filtercourse    = NULL;
-                $groupeventsfrom = NULL;
-                $SESSION->cal_courses_shown = calendar_get_default_courses(true);
-                calendar_set_referring_course(0);
+                $filtercourse = calendar_get_default_courses();
             } else {
                 // Forcibly filter events to include only those from the particular course we are in.
-                $filtercourse    = array($courseshown => $this->page->course);
-                $groupeventsfrom = array($courseshown => 1);
+                $filtercourse = array($courseshown => $this->page->course);
             }
         }
 
-        // We 'll need this later
-        calendar_set_referring_course($courseshown);
+        list($courses, $group, $user) = calendar_set_filters($filtercourse);
 
-        // Be VERY careful with the format for default courses arguments!
-        // Correct formatting is [courseid] => 1 to be concise with moodlelib.php functions.
+        $defaultlookahead = CALENDAR_DEFAULT_UPCOMING_LOOKAHEAD;
+        if (isset($CFG->calendar_lookahead)) {
+            $defaultlookahead = intval($CFG->calendar_lookahead);
+        }
+        $lookahead = get_user_preferences('calendar_lookahead', $defaultlookahead);
 
-        calendar_set_filters($courses, $group, $user, $filtercourse, $groupeventsfrom, false);
-        $events = calendar_get_upcoming($courses, $group, $user,
-                                        get_user_preferences('calendar_lookahead', CALENDAR_UPCOMING_DAYS),
-                                        get_user_preferences('calendar_maxevents', CALENDAR_UPCOMING_MAXEVENTS));
+        $defaultmaxevents = CALENDAR_DEFAULT_UPCOMING_MAXEVENTS;
+        if (isset($CFG->calendar_maxevents)) {
+            $defaultmaxevents = intval($CFG->calendar_maxevents);
+        }
+        $maxevents = get_user_preferences('calendar_maxevents', $defaultmaxevents);
+        $events = calendar_get_upcoming($courses, $group, $user, $lookahead, $maxevents);
 
         if (!empty($this->instance)) {
-            $this->content->text = calendar_get_block_upcoming($events,
-                                   'view.php?view=day&amp;course='.$courseshown.'&amp;');
+            $this->content->text = calendar_get_block_upcoming($events, 'view.php?view=day&amp;course='.$courseshown.'&amp;');
         }
 
         if (empty($this->content->text)) {
-            $this->content->text = '<div class="post">'.
-                                   get_string('noupcomingevents', 'calendar').'</div>';
+            $this->content->text = '<div class="post">'. get_string('noupcomingevents', 'calendar').'</div>';
         }
 
         return $this->content;
index 0f25fb4..c37af10 100644 (file)
@@ -1035,7 +1035,7 @@ function blog_comment_validate($comment_param) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function blog_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function blog_page_type_list($pagetype, $parentcontext, $currentcontext) {
     return array(
         '*'=>get_string('page-x', 'pagetype'),
         'blog-*'=>get_string('page-blog-x', 'blog'),
index 2e6fa67..dd98be3 100644 (file)
@@ -55,26 +55,43 @@ require_login();
 
 $action = optional_param('action', 'new', PARAM_ALPHA);
 $eventid = optional_param('id', 0, PARAM_INT);
-$courseid = optional_param('courseid', 0, PARAM_INT);
+$courseid = optional_param('courseid', SITEID, PARAM_INT);
+$courseid = optional_param('course', $courseid, PARAM_INT);
 $cal_y = optional_param('cal_y', 0, PARAM_INT);
 $cal_m = optional_param('cal_m', 0, PARAM_INT);
 $cal_d = optional_param('cal_d', 0, PARAM_INT);
 
-if ($courseid === 0) {
-    $courseid = optional_param('course', 0, PARAM_INT);
+$url = new moodle_url('/calendar/event.php', array('action' => $action));
+if ($eventid != 0) {
+    $url->param('id', $eventid);
+}
+if ($courseid != SITEID) {
+    $url->param('course', $courseid);
+}
+if ($cal_y !== 0) {
+    $url->param('cal_y', $cal_y);
+}
+if ($cal_m !== 0) {
+    $url->param('cal_m', $cal_m);
+}
+if ($cal_d !== 0) {
+    $url->param('cal_d', $cal_d);
 }
-
-$url = new moodle_url('/calendar/event.php', array('action'=>$action));
-if ($eventid !== 0) $url->param('id', $eventid);
-if ($courseid !== 0) $url->param('course', $courseid);
-if ($cal_y !== 0) $url->param('cal_y', $cal_y);
-if ($cal_m !== 0) $url->param('cal_m', $cal_m);
-if ($cal_d !== 0) $url->param('cal_d', $cal_d);
 $PAGE->set_url($url);
-$PAGE->set_context(get_context_instance(CONTEXT_SYSTEM));
 $PAGE->set_pagelayout('standard');
 
-if ($action === 'delete' && $eventid>0) {
+if ($courseid != SITEID && !empty($courseid)) {
+    $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
+    $courses = array($course->id => $course);
+    $issite = false;
+} else {
+    $course = get_site();
+    $courses = calendar_get_default_courses();
+    $issite = true;
+}
+require_login($course, false);
+
+if ($action === 'delete' && $eventid > 0) {
     $deleteurl = new moodle_url('/calendar/delete.php', array('id'=>$eventid));
     if ($courseid > 0) {
         $deleteurl->param('course', $courseid);
@@ -82,56 +99,10 @@ if ($action === 'delete' && $eventid>0) {
     redirect($deleteurl);
 }
 
-$viewcalendarurl = new moodle_url(CALENDAR_URL.'view.php');
-$viewcalendarurl->params($PAGE->url->params());
-$viewcalendarurl->remove_params(array('id','action'));
-
-$now = usergetdate(time());
-
-if (isguestuser()) {
-    // Guests cannot do anything with events
-    redirect(new moodle_url(CALENDAR_URL.'view.php', array('view'=>'upcoming', 'course'=>$courseid)));
-}
-
-$focus = '';
-
-$site = get_site();
-
-calendar_session_vars();
-
-// If a course has been supplied in the URL, change the filters to show that one
-$courseexists = false;
-if ($courseid > 0) {
-    if ($courseid == SITEID) {
-        // If coming from the site page, show all courses
-        $SESSION->cal_courses_shown = calendar_get_default_courses(true);
-        calendar_set_referring_course(0);
-    } else if ($DB->record_exists('course', array('id'=>$courseid))) {
-        $courseexists = true;
-        // Otherwise show just this one
-        $SESSION->cal_courses_shown = $courseid;
-        calendar_set_referring_course($SESSION->cal_courses_shown);
-    }
-}
-
-if (!empty($SESSION->cal_course_referer)) {
-    // TODO: This is part of the Great $course Hack in Moodle. Replace it at some point.
-    $course = $DB->get_record('course', array('id'=>$SESSION->cal_course_referer));
-} else {
-    $course = $site;
-}
-
-require_login($course, false);
-
 $calendar = new calendar_information($cal_d, $cal_m, $cal_y);
-$calendar->courseid = $courseid;
-
-$strcalendar = get_string('calendar', 'calendar');
-$link = clone($viewcalendarurl);
-$link->param('view', 'upcoming');
+$calendar->prepare_for_view($course, $courses);
 
 $formoptions = new stdClass;
-
 if ($eventid !== 0) {
     $title = get_string('editevent', 'calendar');
     $event = calendar_event::load($eventid);
@@ -148,13 +119,13 @@ if ($eventid !== 0) {
     }
 } else {
     $title = get_string('newevent', 'calendar');
-    calendar_get_allowed_types($formoptions->eventtypes, $USER->id);
+    calendar_get_allowed_types($formoptions->eventtypes, $course);
     $event = new stdClass();
     $event->action = $action;
     $event->course = $courseid;
     $event->timeduration = 0;
     if ($formoptions->eventtypes->courses) {
-        if ($courseexists) {
+        if (!$issite) {
             $event->courseid = $courseid;
             $event->eventtype = 'course';
         } else {
@@ -165,6 +136,7 @@ if ($eventid !== 0) {
     if($cal_y && $cal_m && $cal_d && checkdate($cal_m, $cal_d, $cal_y)) {
         $event->timestart = make_timestamp($cal_y, $cal_m, $cal_d, 0, 0, 0);
     } else if($cal_y && $cal_m && checkdate($cal_m, 1, $cal_y)) {
+        $now = usergetdate(time());
         if($cal_y == $now['year'] && $cal_m == $now['mon']) {
             $event->timestart = make_timestamp($cal_y, $cal_m, $now['mday'], 0, 0, 0);
         } else {
@@ -193,23 +165,31 @@ if ($data) {
     }
 
     $event->update($data);
-    $eventurl = new moodle_url(CALENDAR_URL.'view.php', array('view'=>'day'));
-    if (!empty($event->courseid)) {
+
+    $params = array(
+        'view' => 'day',
+        'cal_d' => date('j', $event->timestart),
+        'cal_m' => date('n', $event->timestart),
+        'cal_y' => date('y', $event->timestart),
+    );
+    $eventurl = new moodle_url('/calendar/view.php', $params);
+    if (!empty($event->courseid) && $event->courseid != SITEID) {
         $eventurl->param('course', $event->courseid);
     }
-    $eventurl->param('cal_d', date('j', $event->timestart));
-    $eventurl->param('cal_m', date('n', $event->timestart));
-    $eventurl->param('cal_y', date('Y', $event->timestart));
     $eventurl->set_anchor('event_'.$event->id);
     redirect($eventurl);
 }
 
-$PAGE->navbar->add($strcalendar, $link);
+$viewcalendarurl = new moodle_url(CALENDAR_URL.'view.php', $PAGE->url->params());
+$viewcalendarurl->remove_params(array('id', 'action'));
+$viewcalendarurl->param('view', 'upcoming');
+$strcalendar = get_string('calendar', 'calendar');
+
+$PAGE->navbar->add($strcalendar, $viewcalendarurl);
 $PAGE->navbar->add($title);
-$PAGE->set_title($site->shortname.': '.$strcalendar.': '.$title);
-$PAGE->set_heading($COURSE->fullname);
+$PAGE->set_title($course->shortname.': '.$strcalendar.': '.$title);
+$PAGE->set_heading($course->fullname);
 
-calendar_set_filters($calendar->courses, $calendar->groups, $calendar->users);
 $renderer = $PAGE->get_renderer('core_calendar');
 $calendar->add_sidecalendar_blocks($renderer);
 
index 46b3436..d43f665 100644 (file)
 require_once('../config.php');
 require_once($CFG->dirroot.'/course/lib.php');
 require_once($CFG->dirroot.'/calendar/lib.php');
-//require_once($CFG->libdir.'/bennu/bennu.inc.php');
 
+if (empty($CFG->enablecalendarexport)) {
+    die('no export');
+}
+
+$courseid = optional_param('course', SITEID, PARAM_INT);
 $action = optional_param('action', '', PARAM_ALPHA);
 $day  = optional_param('cal_d', 0, PARAM_INT);
 $mon  = optional_param('cal_m', 0, PARAM_INT);
 $yr   = optional_param('cal_y', 0, PARAM_INT);
-if ($courseid = optional_param('course', 0, PARAM_INT)) {
-    $course = $DB->get_record('course', array('id'=>$courseid));
+
+if ($courseid != SITEID && !empty($courseid)) {
+    $course = $DB->get_record('course', array('id' => $courseid));
+    $courses = array($course->id => $course);
+    $issite = false;
 } else {
-    $course = NULL;
+    $course = get_site();
+    $courses = calendar_get_default_courses();
+    $issite = true;
 }
+require_course_login($course);
 
 $url = new moodle_url('/calendar/export.php');
 if ($action !== '') {
@@ -79,57 +89,22 @@ if ($course !== NULL) {
 }
 $PAGE->set_url($url);
 
-require_login($course);
-if (!$course) {
-    $PAGE->set_context(get_context_instance(CONTEXT_SYSTEM)); //TODO: wrong
-}
-
-if (empty($CFG->enablecalendarexport)) {
-    die('no export');
-}
-
-$site = get_site();
-
-// Initialize the session variables
-calendar_session_vars();
+$calendar = new calendar_information($day, $mon, $yr);
+$calendar->prepare_for_view($course, $courses);
 
 $pagetitle = get_string('export', 'calendar');
-$navlinks = array();
-$now = usergetdate(time());
 
-if (!empty($courseid) && $course->id != SITEID) {
+// Print title and header
+if ($issite) {
     $PAGE->navbar->add($course->shortname, new moodle_url('/course/view.php', array('id'=>$course->id)));
 }
-
-$calendar = new calendar_information($day, $mon, $yr);
-$calendar->courseid = $courseid;
-
-
-if(!checkdate($mon, $day, $yr)) {
-    $day = intval($now['mday']);
-    $mon = intval($now['mon']);
-    $yr = intval($now['year']);
-}
-$time = make_timestamp($yr, $mon, $day);
-
-if (!isloggedin() or isguestuser()) {
-    $defaultcourses = calendar_get_default_courses();
-    calendar_set_filters($calendar->courses, $calendar->groups, $calendar->users, $defaultcourses, $defaultcourses);
-} else {
-    calendar_set_filters($calendar->courses, $calendar->groups, $calendar->users);
-}
-
-$strcalendar = get_string('calendar', 'calendar');
-$prefsbutton = calendar_preferences_button();
-
-// Print title and header
 $link = new moodle_url(CALENDAR_URL.'view.php', array('view'=>'upcoming', 'course'=>$calendar->courseid));
 $PAGE->navbar->add(get_string('calendar', 'calendar'), calendar_get_link_href($link, $now['mday'], $now['mon'], $now['year']));
 $PAGE->navbar->add($pagetitle);
 
-$PAGE->set_title($site->shortname.': '.$strcalendar.': '.$pagetitle);
-$PAGE->set_heading($COURSE->fullname);
-$PAGE->set_button($prefsbutton);
+$PAGE->set_title($course->shortname.': '.get_string('calendar', 'calendar').': '.$pagetitle);
+$PAGE->set_heading($course->fullname);
+$PAGE->set_button(calendar_preferences_button($course));
 $PAGE->set_pagelayout('standard');
 
 $renderer = $PAGE->get_renderer('core_calendar');
@@ -139,19 +114,26 @@ echo $OUTPUT->header();
 echo $renderer->start_layout();
 switch($action) {
     case 'advanced':
-    break;
+        // Why nothing?
+        break;
     case '':
     default:
+        $weekend = CALENDAR_DEFAULT_WEEKEND;
+        if (isset($CFG->calendar_weekend)) {
+            $weekend = intval($CFG->calendar_weekend);
+        }
         $username = $USER->username;
         $authtoken = sha1($USER->username . $USER->password . $CFG->calendar_exportsalt);
         // Let's populate some vars to let "common tasks" be somewhat smart...
         // If today it's weekend, give the "next week" option
-        $allownextweek  = CALENDAR_WEEKEND & (1 << $now['wday']);
+        $allownextweek  = $weekend & (1 << $now['wday']);
         // If it's the last week of the month, give the "next month" option
         $allownextmonth = calendar_days_in_month($now['mon'], $now['year']) - $now['mday'] < 7;
         // If today it's weekend but tomorrow it isn't, do NOT give the "this week" option
-        $allowthisweek  = !((CALENDAR_WEEKEND & (1 << $now['wday'])) && !(CALENDAR_WEEKEND & (1 << (($now['wday'] + 1) % 7))));
+        $allowthisweek  = !(($weekend & (1 << $now['wday'])) && !($weekend & (1 << (($now['wday'] + 1) % 7))));
         echo $renderer->basic_export_form($allowthisweek, $allownextweek, $allownextmonth, $username, $authtoken);
+        break;
 }
+
 echo $renderer->complete_layout();
 echo $OUTPUT->footer();
index 926a551..9c963bc 100644 (file)
@@ -45,20 +45,29 @@ define('CALENDAR_DEFAULT_STARTING_WEEKDAY',   1);
 // This is a packed bitfield: day X is "weekend" if $field & (1 << X) is true
 // Default value = 65 = 64 + 1 = 2^6 + 2^0 = Saturday & Sunday
 define('CALENDAR_DEFAULT_WEEKEND',            65);
-define('CALENDAR_UPCOMING_DAYS', isset($CFG->calendar_lookahead) ? intval($CFG->calendar_lookahead) : CALENDAR_DEFAULT_UPCOMING_LOOKAHEAD);
-define('CALENDAR_UPCOMING_MAXEVENTS', isset($CFG->calendar_maxevents) ? intval($CFG->calendar_maxevents) : CALENDAR_DEFAULT_UPCOMING_MAXEVENTS);
-define('CALENDAR_WEEKEND', isset($CFG->calendar_weekend) ? intval($CFG->calendar_weekend) : CALENDAR_DEFAULT_WEEKEND);
 define('CALENDAR_URL', $CFG->wwwroot.'/calendar/');
 define('CALENDAR_TF_24', '%H:%M');
 define('CALENDAR_TF_12', '%I:%M %p');
 
+define('CALENDAR_EVENT_GLOBAL', 1);
+define('CALENDAR_EVENT_COURSE', 2);
+define('CALENDAR_EVENT_GROUP', 4);
+define('CALENDAR_EVENT_USER', 8);
+
 /**
  * CALENDAR_STARTING_WEEKDAY has since been deprecated please call calendar_get_starting_weekday() instead
  * @deprecated
  */
 define('CALENDAR_STARTING_WEEKDAY', CALENDAR_DEFAULT_STARTING_WEEKDAY);
 
-$CALENDARDAYS = array('sunday','monday','tuesday','wednesday','thursday','friday','saturday');
+/**
+ * Return the days of the week
+ *
+ * @return array
+ */
+function calendar_get_days() {
+    return array('sunday', 'monday', 'tuesday', 'wednesday', 'thursday', 'friday', 'saturday');
+}
 
 /**
  * Gets the first day of the week
@@ -197,8 +206,7 @@ function calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_y
     calendar_events_by_day($events, $m, $y, $eventsbyday, $durationbyday, $typesbyday, $courses);
 
     //Accessibility: added summary and <abbr> elements.
-    ///global $CALENDARDAYS; appears to be broken.
-    $days_title = array('sunday','monday','tuesday','wednesday','thursday','friday','saturday');
+    $days_title = calendar_get_days();
 
     $summary = get_string('calendarheading', 'calendar', userdate(make_timestamp($y, $m), get_string('strftimemonthyear')));
     $summary = get_string('tabledata', 'access', $summary);
@@ -224,6 +232,11 @@ function calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_y
         $content .= '<td class="dayblank">&nbsp;</td>'."\n";
     }
 
+    $weekend = CALENDAR_DEFAULT_WEEKEND;
+    if (isset($CFG->calendar_weekend)) {
+        $weekend = intval($CFG->calendar_weekend);
+    }
+
     // Now display all the calendar
     for($day = 1; $day <= $display->maxdays; ++$day, ++$dayweek) {
         if($dayweek > $display->maxwday) {
@@ -234,7 +247,7 @@ function calendar_get_mini($courses, $groups, $users, $cal_month = false, $cal_y
 
         // Reset vars
         $cell = '';
-        if(CALENDAR_WEEKEND & (1 << ($dayweek % 7))) {
+        if ($weekend & (1 << ($dayweek % 7))) {
             // Weekend. This is true no matter what the exact range is.
             $class = 'weekend day';
         } else {
@@ -665,7 +678,7 @@ function calendar_get_events($tstart, $tend, $users, $groups, $courses, $withdur
 }
 
 function calendar_top_controls($type, $data) {
-    global $CFG, $CALENDARDAYS;
+    global $CFG;
     $content = '';
     if(!isset($data['d'])) {
         $data['d'] = 1;
@@ -786,11 +799,12 @@ function calendar_top_controls($type, $data) {
             $content .= html_writer::end_tag('div')."\n";
             break;
         case 'day':
+            $days = calendar_get_days();
             $data['d'] = $date['mday']; // Just for convenience
             $prevdate = usergetdate(make_timestamp($data['y'], $data['m'], $data['d'] - 1));
             $nextdate = usergetdate(make_timestamp($data['y'], $data['m'], $data['d'] + 1));
-            $prevname = calendar_wday_name($CALENDARDAYS[$prevdate['wday']]);
-            $nextname = calendar_wday_name($CALENDARDAYS[$nextdate['wday']]);
+            $prevname = calendar_wday_name($days[$prevdate['wday']]);
+            $nextname = calendar_wday_name($days[$nextdate['wday']]);
             $prevlink = calendar_get_link_previous($prevname, 'view.php?view=day'.$courseid.'&amp;', $prevdate['mday'], $prevdate['mon'], $prevdate['year']);
             $nextlink = calendar_get_link_next($nextname, 'view.php?view=day'.$courseid.'&amp;', $nextdate['mday'], $nextdate['mon'], $nextdate['year']);
 
@@ -814,79 +828,61 @@ function calendar_top_controls($type, $data) {
     return $content;
 }
 
-function calendar_filter_controls($type, $vars = NULL, $course = NULL, $courses = NULL) {
-    global $CFG, $SESSION, $USER, $OUTPUT;
+function calendar_filter_controls(moodle_url $returnurl) {
+    global $CFG, $USER, $OUTPUT;
 
     $groupevents = true;
-    $getvars = '';
 
     $id = optional_param( 'id',0,PARAM_INT );
 
-    switch($type) {
-        case 'event':
-        case 'upcoming':
-        case 'day':
-        case 'month':
-            $getvars = '&amp;from='.$type;
-        break;
-        case 'course':
-            if ($id > 0) {
-                $getvars = '&amp;from=course&amp;id='.$id;
-            } else {
-                $getvars = '&amp;from=course';
-            }
-            if (isset($course->groupmode) and $course->groupmode == NOGROUPS and $course->groupmodeforce) {
-                $groupevents = false;
-            }
-        break;
-    }
-
-    if (!empty($vars)) {
-        $getvars .= '&amp;'.$vars;
-    }
+    $seturl = new moodle_url('/calendar/set.php', array('return' => $returnurl));
 
     $content = '<table>';
-
     $content .= '<tr>';
-    if($SESSION->cal_show_global) {
-        $content .= '<td class="eventskey calendar_event_global" style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/hide') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_hideglobal', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".CALENDAR_URL.'set.php?var=showglobal'.$getvars."'".'" /></td>';
-        $content .= '<td><a href="'.CALENDAR_URL.'set.php?var=showglobal'.$getvars.'" title="'.get_string('tt_hideglobal', 'calendar').'">'.get_string('global', 'calendar').'</a></td>'."\n";
+
+    $seturl->param('var', 'showglobal');
+    if (calendar_show_event_type(CALENDAR_EVENT_GLOBAL)) {
+        $content .= '<td class="eventskey calendar_event_global" style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/hide') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_hideglobal', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".$seturl."'".'" /></td>';
+        $content .= '<td><a href="'.$seturl.'" title="'.get_string('tt_hideglobal', 'calendar').'">'.get_string('global', 'calendar').'</a></td>'."\n";
     } else {
-        $content .= '<td style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/show') . '" class="iconsmall" alt="'.get_string('show').'" title="'.get_string('tt_showglobal', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".CALENDAR_URL.'set.php?var=showglobal'.$getvars."'".'" /></td>';
-        $content .= '<td><a href="'.CALENDAR_URL.'set.php?var=showglobal'.$getvars.'" title="'.get_string('tt_showglobal', 'calendar').'">'.get_string('global', 'calendar').'</a></td>'."\n";
+        $content .= '<td style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/show') . '" class="iconsmall" alt="'.get_string('show').'" title="'.get_string('tt_showglobal', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".$seturl."'".'" /></td>';
+        $content .= '<td><a href="'.$seturl.'" title="'.get_string('tt_showglobal', 'calendar').'">'.get_string('global', 'calendar').'</a></td>'."\n";
     }
-    if($SESSION->cal_show_course) {
-        $content .= '<td class="eventskey calendar_event_course" style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/hide') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_hidecourse', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".CALENDAR_URL.'set.php?var=showcourses'.$getvars."'".'" /></td>';
-        $content .= '<td><a href="'.CALENDAR_URL.'set.php?var=showcourses'.$getvars.'" title="'.get_string('tt_hidecourse', 'calendar').'">'.get_string('course', 'calendar').'</a></td>'."\n";
-    } else {
-        $content .= '<td style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/show') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_showcourse', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".CALENDAR_URL.'set.php?var=showcourses'.$getvars."'".'" /></td>';
-        $content .= '<td><a href="'.CALENDAR_URL.'set.php?var=showcourses'.$getvars.'" title="'.get_string('tt_showcourse', 'calendar').'">'.get_string('course', 'calendar').'</a></td>'."\n";
 
+    $seturl->param('var', 'showcourses');
+    if (calendar_show_event_type(CALENDAR_EVENT_COURSE)) {
+        $content .= '<td class="eventskey calendar_event_course" style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/hide') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_hidecourse', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".$seturl."'".'" /></td>';
+        $content .= '<td><a href="'.$seturl.'" title="'.get_string('tt_hidecourse', 'calendar').'">'.get_string('course', 'calendar').'</a></td>'."\n";
+    } else {
+        $content .= '<td style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/show') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_showcourse', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".$seturl."'".'" /></td>';
+        $content .= '<td><a href="'.$seturl.'" title="'.get_string('tt_showcourse', 'calendar').'">'.get_string('course', 'calendar').'</a></td>'."\n";
     }
 
-
     if (isloggedin() && !isguestuser()) {
         $content .= "</tr>\n<tr>";
 
-        if($groupevents) {
+        if ($groupevents) {
             // This course MIGHT have group events defined, so show the filter
-            if($SESSION->cal_show_groups) {
-                $content .= '<td class="eventskey calendar_event_group" style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/hide') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_hidegroups', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".CALENDAR_URL.'set.php?var=showgroups'.$getvars."'".'" /></td>';
-                $content .= '<td><a href="'.CALENDAR_URL.'set.php?var=showgroups'.$getvars.'" title="'.get_string('tt_hidegroups', 'calendar').'">'.get_string('group', 'calendar').'</a></td>'."\n";
+            $seturl->param('var', 'showgroups');
+            if (calendar_show_event_type(CALENDAR_EVENT_GROUP)) {
+                $content .= '<td class="eventskey calendar_event_group" style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/hide') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_hidegroups', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".$seturl."'".'" /></td>';
+                $content .= '<td><a href="'.$seturl.'" title="'.get_string('tt_hidegroups', 'calendar').'">'.get_string('group', 'calendar').'</a></td>'."\n";
             } else {
-                $content .= '<td style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/show') . '" class="iconsmall" alt="'.get_string('show').'" title="'.get_string('tt_showgroups', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".CALENDAR_URL.'set.php?var=showgroups'.$getvars."'".'" /></td>';
-                $content .= '<td><a href="'.CALENDAR_URL.'set.php?var=showgroups'.$getvars.'" title="'.get_string('tt_showgroups', 'calendar').'">'.get_string('group', 'calendar').'</a></td>'."\n";
+                $content .= '<td style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/show') . '" class="iconsmall" alt="'.get_string('show').'" title="'.get_string('tt_showgroups', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".$seturl."'".'" /></td>';
+                $content .= '<td><a href="'.$seturl.'" title="'.get_string('tt_showgroups', 'calendar').'">'.get_string('group', 'calendar').'</a></td>'."\n";
             }
         } else {
             // This course CANNOT have group events, so lose the filter
             $content .= '<td style="width: 11px;"></td><td>&nbsp;</td>'."\n";
         }
-        if($SESSION->cal_show_user) {
-            $content .= '<td class="eventskey calendar_event_user" style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/hide') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_hideuser', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".CALENDAR_URL.'set.php?var=showuser'.$getvars."'".'" /></td>';
-            $content .= '<td><a href="'.CALENDAR_URL.'set.php?var=showuser'.$getvars.'" title="'.get_string('tt_hideuser', 'calendar').'">'.get_string('user', 'calendar').'</a></td>'."\n";
+
+        $seturl->param('var', 'showuser');
+        if (calendar_show_event_type(CALENDAR_EVENT_USER)) {
+            $content .= '<td class="eventskey calendar_event_user" style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/hide') . '" class="iconsmall" alt="'.get_string('hide').'" title="'.get_string('tt_hideuser', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".$seturl."'".'" /></td>';
+            $content .= '<td><a href="'.$seturl.'" title="'.get_string('tt_hideuser', 'calendar').'">'.get_string('user', 'calendar').'</a></td>'."\n";
         } else {
-            $content .= '<td style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/show') . '" class="iconsmall" alt="'.get_string('show').'" title="'.get_string('tt_showuser', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".CALENDAR_URL.'set.php?var=showuser'.$getvars."'".'" /></td>';
-            $content .= '<td><a href="'.CALENDAR_URL.'set.php?var=showuser'.$getvars.'" title="'.get_string('tt_showuser', 'calendar').'">'.get_string('user', 'calendar').'</a></td>'."\n";
+            $content .= '<td style="width: 11px;"><img src="'.$OUTPUT->pix_url('t/show') . '" class="iconsmall" alt="'.get_string('show').'" title="'.get_string('tt_showuser', 'calendar').'" style="cursor:pointer" onclick="location.href='."'".$seturl."'".'" /></td>';
+            $content .= '<td><a href="'.$seturl.'" title="'.get_string('tt_showuser', 'calendar').'">'.get_string('user', 'calendar').'</a></td>'."\n";
         }
     }
     $content .= "</tr>\n</table>\n";
@@ -1204,212 +1200,89 @@ function calendar_get_course_cached(&$coursecache, $courseid) {
     return $coursecache[$courseid];
 }
 
-function calendar_session_vars($course=null) {
-    global $SESSION, $USER;
+/**
+ * Returns the courses to load events for, the
+ *
+ * @global moodle_database $DB
+ * @param array $courseeventsfrom An array of courses to load calendar events for
+ * @param bool $ignorefilters
+ * @return array An array of courses, groups, and user to load calendar events for based upon filters
+ */
+function calendar_set_filters(array $courseeventsfrom, $ignorefilters = false) {
+    global $USER, $CFG, $DB;
 
-    if(!isset($SESSION->cal_course_referer)) {
-        $SESSION->cal_course_referer = 0;
-    }
-    if(!isset($SESSION->cal_show_global)) {
-        $SESSION->cal_show_global = true;
-    }
-    if(!isset($SESSION->cal_show_groups)) {
-        $SESSION->cal_show_groups = true;
-    }
-    if(!isset($SESSION->cal_show_course)) {
-        $SESSION->cal_show_course = true;
-    }
-    if(!isset($SESSION->cal_show_user)) {
-        $SESSION->cal_show_user = true;
-    }
-    if ($course !== null) {
-        // speedup hack for calendar related blocks
-        if(isset($course->coursenode)) {
-            // coursenode has been set up, which seems to break things further down the line.
-            // Use a clone of $course with coursenode removed.
-            $course = clone $course;
-            unset($course->coursenode);
+    // For backwards compatability we have to check whether the courses array contains
+    // just id's in which case we need to load course objects.
+    $coursestoload = array();
+    foreach ($courseeventsfrom as $id => $something) {
+        if (!is_object($something)) {
+            $coursestoload[] = $id;
+            unset($courseeventsfrom[$id]);
         }
-        $SESSION->cal_courses_shown = array($course->id => $course);
-    } else {
-        $SESSION->cal_courses_shown = calendar_get_default_courses(true);
     }
-    if(empty($SESSION->cal_users_shown)) {
-        // The empty() instead of !isset() here makes a whole world of difference,
-        // as it will automatically change to the user's id when the user first logs
-        // in. With !isset(), it would never do that.
-        $SESSION->cal_users_shown = isloggedin() ? $USER->id : false;
-    } else if(is_numeric($SESSION->cal_users_shown) && isloggedin() && $SESSION->cal_users_shown != $USER->id) {
-        // Follow the white rabbit, for example if a teacher logs in as a student
-        $SESSION->cal_users_shown = $USER->id;
+    if (!empty($coursestoload)) {
+        // TODO remove this in 2.2
+        debugging('calendar_set_filters now preferes an array of course objects with preloaded contexts', DEBUG_DEVELOPER);
+        $courseeventsfrom = array_merge($courseeventsfrom, $DB->get_records_list('course', 'id', $coursestoload));
     }
-}
 
-function calendar_set_referring_course($courseid) {
-    global $SESSION;
-    $SESSION->cal_course_referer = intval($courseid);
-}
+    $courses = array();
+    $user = false;
+    $group = false;
 
-function calendar_set_filters(&$courses, &$group, &$user, $courseeventsfrom = NULL, $groupeventsfrom = NULL, $ignorefilters = false) {
-    global $SESSION, $USER, $CFG, $DB;
-
-    // Insidious bug-wannabe: setting $SESSION->cal_courses_shown to $course->id would cause
-    // the code to function incorrectly UNLESS we convert it to an integer. One case where
-    // PHP's loose type system works against us.
-    if(is_string($SESSION->cal_courses_shown)) {
-        $SESSION->cal_courses_shown = intval($SESSION->cal_courses_shown);
-    }
-    if($courseeventsfrom === NULL) {
-        $courseeventsfrom = $SESSION->cal_courses_shown;
-    }
-
-    // MDL-9059, $courseeventsfrom can be an int, or an array of ints, or an array of course objects
-    // convert all to array of objects
-    // we probably should do some clean up and make sure that session is set to use the proper form
-    if (is_int($courseeventsfrom)) { // case of an int, e.g. calendar view page
-        $c = array();
-        $c[$courseeventsfrom] = $DB->get_record('course', array('id'=>$courseeventsfrom));
-        $courseeventsfrom = $c;
-    } else if (is_array($courseeventsfrom)) { // case of an array of ints, e.g. course home page
-        foreach ($courseeventsfrom as $i=>$courseid) { // TODO: this seems wrong, the array is often constructed as [courseid] => 1 ???
-            if (is_int($courseid)) {
-                $courseeventsfrom[$i] = $DB->get_record('course', array('id'=>$courseid));
-            }
-        }
-    }
+    $isloggedin = isloggedin();
 
-    if($groupeventsfrom === NULL) {
-        $groupeventsfrom = $SESSION->cal_courses_shown;
+    if ($ignorefilters || calendar_show_event_type(CALENDAR_EVENT_COURSE)) {
+        $courses = array_keys($courseeventsfrom);
     }
-
-    if(($SESSION->cal_show_course && $SESSION->cal_show_global) || $ignorefilters) {
-        if(is_int($courseeventsfrom)) {
-            $courses = array(SITEID, $courseeventsfrom);
-        }
-        else if(is_array($courseeventsfrom)) {
-            $courses = array_keys($courseeventsfrom);
-            $courses[] = SITEID;
-        }
+    if ($ignorefilters || calendar_show_event_type(CALENDAR_EVENT_GLOBAL)) {
+        $courses[] = SITEID;
     }
-    else if($SESSION->cal_show_course) {
-        if(is_int($courseeventsfrom)) {
-            $courses = array($courseeventsfrom);
-        }
-        else if(is_array($courseeventsfrom)) {
-            $courses = array_keys($courseeventsfrom);
-        }
-        $courses = array_diff($courses, array(SITEID));
-    }
-    else if($SESSION->cal_show_global) {
-        $courses = array(SITEID);
-    }
-    else {
-        $courses = false;
-    }
-    //BUG 6130 clean $courses array as SESSION has bad entries.
-    // [pj] TODO: See if this has to do with my new change in get_default_courses and can be taken out
-    if (is_array($courses)) {
-        foreach ($courses as $index => $value) {
-            if (empty($value)) unset($courses[$index]);
-        }
+    $courses = array_unique($courses);
+    sort($courses);
 
+    if (!empty($courses) && in_array(SITEID, $courses)) {
         // Sort courses for consistent colour highlighting
         // Effectively ignoring SITEID as setting as last course id
         $key = array_search(SITEID, $courses);
-        if ($key !== false) {
-            unset($courses[$key]);
-            sort($courses);
-            $courses[] = SITEID;
-        } else {
-            sort($courses);
-        }
+        unset($courses[$key]);
+        $courses[] = SITEID;
     }
 
-    if($SESSION->cal_show_user || $ignorefilters) {
-        // This doesn't work for arrays yet (maybe someday it will)
-        $user = $SESSION->cal_users_shown;
+    if ($ignorefilters || ($isloggedin && calendar_show_event_type(CALENDAR_EVENT_USER))) {
+        $user = $USER->id;
     }
-    else {
-        $user = false;
-    }
-    if($SESSION->cal_show_groups || $ignorefilters) {
-        if(is_int($groupeventsfrom)) {
-            $groupcourses = array($groupeventsfrom);
-        }
-        else if(is_array($groupeventsfrom)) {
-            $groupcourses = array_keys($groupeventsfrom);
-        }
 
-        // XXX TODO: not sure how to replace $CFG->calendar_adminseesall
-        if(has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_SYSTEM)) && !empty($CFG->calendar_adminseesall)) {
+    if (!empty($courseeventsfrom) && (calendar_show_event_type(CALENDAR_EVENT_GROUP) || $ignorefilters)) {
+
+        if (!empty($CFG->calendar_adminseesall) && has_capability('moodle/calendar:manageentries', get_system_context())) {
             $group = true;
-        }
-        else {
-            $grouparray = array();
+        } else if ($isloggedin) {
+            $groupids = array();
 
             // We already have the courses to examine in $courses
             // For each course...
-
-            foreach($groupcourses as $courseid) {
-
-                if (!isset($courseeventsfrom[$courseid]->context)) { // SHOULD be set MDL-11221
-                    if (is_object($courseeventsfrom[$courseid])) {
-                        $courseeventsfrom[$courseid]->context = get_context_instance(CONTEXT_COURSE, $courseid);
-                    }
-                }
-
+            foreach ($courseeventsfrom as $courseid => $course) {
                 // If the user is an editing teacher in there,
-                if (isloggedin() && isset($courseeventsfrom[$courseid]->context) && has_capability('moodle/calendar:manageentries', $courseeventsfrom[$courseid]->context)) {
+                if (!empty($USER->groupmember[$course->id])) {
+                    // We've already cached the users groups for this course so we can just use that
+                    $groupids = array_merge($groupids, $USER->groupmember[$course->id]);
+                } else if (($course->groupmode != NOGROUPS || !$course->groupmodeforce) && has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_COURSE, $course->id))) {
                     // If this course has groups, show events from all of them
-                    if(is_int($groupeventsfrom)) {
-                        if (is_object($courseeventsfrom[$courseid])) { // SHOULD be set MDL-11221
-                            $courserecord = $courseeventsfrom[$courseid];
-                        } else {
-                            $courserecord = $DB->get_record('course', array('id'=>$courseid));
-                        }
-                        $courserecord = $DB->get_record('course', array('id'=>$courseid));
-                        if ($courserecord->groupmode != NOGROUPS || !$courserecord->groupmodeforce) {
-                            $groupids[] = $courseid;
-                        }
-                    }
-                    else if(isset($SESSION->cal_courses_shown[$courseid]) && ($SESSION->cal_courses_shown[$courseid]->groupmode != NOGROUPS || !$SESSION->cal_courses_shown[$courseid]->groupmodeforce)) {
-                        $groupids[] = $courseid;
-                    }
-                }
-
-                // Otherwise (not editing teacher) show events from the group he is a member of
-                else if(isset($USER->groupmember[$courseid])) {
-                    //changed to 2D array
-                    foreach ($USER->groupmember[$courseid] as $groupid){
-                        $grouparray[] = $groupid;
-                    }
+                    $coursegroups = groups_get_user_groups($course->id, $USER->id);
+                    $groupids = array_merge($groupids, $coursegroups['0']);
                 }
             }
-
             if (!empty($groupids)) {
-                $sql = "SELECT *
-                        FROM {groups}
-                        WHERE courseid IN (".implode(',', $groupids).')';
-
-                if ($grouprecords = $DB->get_records_sql($sql, null)) {
-                    foreach ($grouprecords as $grouprecord) {
-                        $grouparray[] = $grouprecord->id;
-                    }
-                }
-            }
-
-            if(empty($grouparray)) {
-                $group = false;
-            }
-            else {
-                $group = $grouparray;
+                $group = $groupids;
             }
         }
-
     }
-    else {
-        $group = false;
+    if (empty($courses)) {
+        $courses = false;
     }
+
+    return array($courses, $group, $user);
 }
 
 function calendar_edit_event_allowed($event) {
@@ -1454,23 +1327,32 @@ function calendar_edit_event_allowed($event) {
     return false;
 }
 
-function calendar_get_default_courses($ignoreref = false) {
-    global $USER, $CFG, $SESSION, $DB;
-
-    if(!empty($SESSION->cal_course_referer) && !$ignoreref) {
-        return array($SESSION->cal_course_referer => 1);
-    }
+/**
+ * Returns the default courses to display on the calendar when there isn't a specific
+ * course to display.
+ *
+ * @global moodle_database $DB
+ * @return array Array of courses to display
+ */
+function calendar_get_default_courses() {
+    global $CFG, $DB;
 
     if (!isloggedin()) {
         return array();
     }
 
     $courses = array();
-    if (has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_SYSTEM))) {
-        if (!empty($CFG->calendar_adminseesall)) {
-            $courses = $DB->get_records_sql('SELECT id, 1 FROM {course}');
-            return $courses;
+    if (!empty($CFG->calendar_adminseesall) && has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_SYSTEM))) {
+        list ($select, $join) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx');
+        $sql = "SELECT c.* $select
+                  FROM {course} c
+                  JOIN {event} e ON e.courseid = c.id
+                  $join";
+        $courses = $DB->get_records_sql($sql, null, 0, 20);
+        foreach ($courses as $course) {
+            context_instance_preload($course);
         }
+        return $courses;
     }
 
     $courses = enrol_get_my_courses();
@@ -1478,17 +1360,15 @@ function calendar_get_default_courses($ignoreref = false) {
     return $courses;
 }
 
-function calendar_preferences_button() {
-    global $CFG, $USER;
+function calendar_preferences_button(stdClass $course) {
+    global $OUTPUT;
 
     // Guests have no preferences
     if (!isloggedin() || isguestuser()) {
         return '';
     }
 
-    return "<form method=\"get\" ".
-           " action=\"$CFG->wwwroot/calendar/preferences.php\">".
-           "<div><input type=\"submit\" value=\"".get_string("preferences", "calendar")." ...\" /></div></form>";
+    return $OUTPUT->single_button(new moodle_url('/calendar/preferences.php', array('course' => $course->id)), get_string("preferences", "calendar"));
 }
 
 function calendar_format_event_time($event, $now, $linkparams = null, $usecommonwords = true, $showtime=0) {
@@ -1588,61 +1468,93 @@ function calendar_print_month_selector($name, $selected) {
     echo html_writer::select($months, $name, $selected, false);
 }
 
-function calendar_get_filters_status() {
-    global $SESSION;
-
-    $status = 0;
-    if($SESSION->cal_show_global) {
-        $status += 1;
+/**
+ * Checks to see if the requested type of event should be shown for the given user.
+ *
+ * @param CALENDAR_EVENT_GLOBAL|CALENDAR_EVENT_COURSE|CALENDAR_EVENT_GROUP|CALENDAR_EVENT_USER $type
+ *          The type to check the display for (default is to display all)
+ * @param stdClass|int|null $user The user to check for - by default the current user
+ * @return bool True if the tyep should be displayed false otherwise
+ */
+function calendar_show_event_type($type, $user = null) {
+    $default = CALENDAR_EVENT_GLOBAL + CALENDAR_EVENT_COURSE + CALENDAR_EVENT_GROUP + CALENDAR_EVENT_USER;
+    if (get_user_preferences('calendar_persistflt', 0, $user) === 0) {
+        global $SESSION;
+        if (!isset($SESSION->calendarshoweventtype)) {
+            $SESSION->calendarshoweventtype = $default;
+        }
+        return $SESSION->calendarshoweventtype & $type;
+    } else {
+        return get_user_preferences('calendar_savedflt', $default, $user) & $type;
     }
-    if($SESSION->cal_show_course) {
-        $status += 2;
+}
+
+/**
+ * Sets the display of the event type given $display.
+ * If $display = true the event type will be shown.
+ * If $display = false the event type will NOT be shown.
+ * If $display = null the current value will be toggled and saved.
+ *
+ * @param CALENDAR_EVENT_GLOBAL|CALENDAR_EVENT_COURSE|CALENDAR_EVENT_GROUP|CALENDAR_EVENT_USER $type
+ * @param true|false|null $display
+ * @param stdClass|int|null $user
+ */
+function calendar_set_event_type_display($type, $display = null, $user = null) {
+    $persist = get_user_preferences('calendar_persistflt', 0, $user);
+    $default = CALENDAR_EVENT_GLOBAL + CALENDAR_EVENT_COURSE + CALENDAR_EVENT_GROUP + CALENDAR_EVENT_USER;
+    if ($persist === 0) {
+        global $SESSION;
+        if (!isset($SESSION->calendarshoweventtype)) {
+            $SESSION->calendarshoweventtype = $default;
+        }
+        $preference = $SESSION->calendarshoweventtype;
+    } else {
+        $preference = get_user_preferences('calendar_savedflt', $default, $user);
     }
-    if($SESSION->cal_show_groups) {
-        $status += 4;
+    $current = $preference & $type;
+    if ($display === null) {
+        $display = !$current;
     }
-    if($SESSION->cal_show_user) {
-        $status += 8;
+    if ($display && !$current) {
+        $preference += $type;
+    } else if (!$display && $current) {
+        $preference -= $type;
     }
-    return $status;
-}
-
-function calendar_set_filters_status($packed_bitfield) {
-    global $SESSION, $USER;
-
-    if (!isloggedin()) {
-        return false;
+    if ($persist === 0) {
+        $SESSION->calendarshoweventtype = $preference;
+    } else {
+        if ($preference == $default) {
+            unset_user_preference('calendar_savedflt', $user);
+        } else {
+            set_user_preference('calendar_savedflt', $preference, $user);
+        }
     }
-
-    $SESSION->cal_show_global = ($packed_bitfield & 1);
-    $SESSION->cal_show_course = ($packed_bitfield & 2);
-    $SESSION->cal_show_groups = ($packed_bitfield & 4);
-    $SESSION->cal_show_user   = ($packed_bitfield & 8);
-
-    return true;
 }
 
-function calendar_get_allowed_types(&$allowed) {
-    global $USER, $CFG, $SESSION, $DB;
-    $sitecontext = get_context_instance(CONTEXT_SYSTEM);
-    $allowed->user = has_capability('moodle/calendar:manageownentries', $sitecontext);
+function calendar_get_allowed_types(&$allowed, $course = null) {
+    global $USER, $CFG, $DB;
+    $allowed->user = has_capability('moodle/calendar:manageownentries', get_system_context());
     $allowed->groups = false; // This may change just below
     $allowed->courses = false; // This may change just below
     $allowed->site = has_capability('moodle/calendar:manageentries', get_context_instance(CONTEXT_COURSE, SITEID));
 
-    if(!empty($SESSION->cal_course_referer) && $SESSION->cal_course_referer != SITEID) {
-        $course = $DB->get_record('course', array('id'=>$SESSION->cal_course_referer));
-        $coursecontext = get_context_instance(CONTEXT_COURSE, $SESSION->cal_course_referer);
+    if (!empty($course)) {
+        if (!is_object($course)) {
+            $course = $DB->get_record('course', array('id' => $course), '*', MUST_EXIST);
+        }
+        if ($course->id != SITEID) {
+            $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
 
-        if(has_capability('moodle/calendar:manageentries', $coursecontext)) {
-            $allowed->courses = array($course->id => 1);
+            if (has_capability('moodle/calendar:manageentries', $coursecontext)) {
+                $allowed->courses = array($course->id => 1);
 
-            if($course->groupmode != NOGROUPS || !$course->groupmodeforce) {
-                $allowed->groups = groups_get_all_groups($SESSION->cal_course_referer);
-            }
-        } else if(has_capability('moodle/calendar:managegroupentries', $coursecontext)) {
-            if($course->groupmode != NOGROUPS || !$course->groupmodeforce) {
-                $allowed->groups = groups_get_all_groups($SESSION->cal_course_referer, $USER->id);
+                if ($course->groupmode != NOGROUPS || !$course->groupmodeforce) {
+                    $allowed->groups = groups_get_all_groups($course->id);
+                }
+            } else if (has_capability('moodle/calendar:managegroupentries', $coursecontext)) {
+                if($course->groupmode != NOGROUPS || !$course->groupmodeforce) {
+                    $allowed->groups = groups_get_all_groups($course->id);
+                }
             }
         }
     }
@@ -1653,8 +1565,11 @@ function calendar_get_allowed_types(&$allowed) {
  * used to print the "New Event" button
  * @return bool
  */
-function calendar_user_can_add_event() {
-    calendar_get_allowed_types($allowed);
+function calendar_user_can_add_event($course) {
+    if (!isloggedin() || isguestuser()) {
+        return false;
+    }
+    calendar_get_allowed_types($allowed, $course);
     return (bool)($allowed->user || $allowed->groups || $allowed->courses || $allowed->site);
 }
 
@@ -2460,6 +2375,21 @@ class calendar_information {
         $this->year = $year;
     }
 
+    /**
+     *
+     * @param stdClass $course
+     * @param array $coursestoload An array of courses [$course->id => $course]
+     * @param type $ignorefilters
+     */
+    public function prepare_for_view(stdClass $course, array $coursestoload, $ignorefilters = false) {
+        $this->courseid = $course->id;
+        $this->course = $course;
+        list($courses, $group, $user) = calendar_set_filters($coursestoload, $ignorefilters);
+        $this->courses = $courses;
+        $this->groups = $group;
+        $this->users = $user;
+    }
+
     /**
      * Ensures the date for the calendar is correct and either sets it to now
      * or throws a moodle_exception if not
index a0f7c8d..a36c9f3 100644 (file)
@@ -6,28 +6,35 @@ require_once('../config.php');
 require_once($CFG->dirroot.'/calendar/lib.php');
 require_once($CFG->dirroot.'/calendar/preferences_form.php');
 
-$course = $site = get_site();
-if (!empty($SESSION->cal_course_referer)) {
-    $course = $DB->get_record('course', array('id'=>$SESSION->cal_course_referer), '*', MUST_EXIST);
-}
+$courseid = required_param('course', PARAM_INT);
+$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
+
+$PAGE->set_url('/calendar/preferences.php', array('id' => $courseid));
+$PAGE->set_pagelayout('standard');
 
-$PAGE->set_url('/calendar/preferences.php');
+require_login($course);
 
-if ($course->id != SITEID) {
-    require_login($course);
+if ($courseid == SITEID) {
+    $viewurl = new moodle_url('/calendar/view.php', array('view' => 'month'));
 } else {
-    require_login();
-    $PAGE->set_context(get_context_instance(CONTEXT_SYSTEM)); //TODO: wrong
+    $viewurl = new moodle_url('/calendar/view.php', array('view' => 'month', 'course' => $courseid));
 }
-// Initialize the session variables
-calendar_session_vars();
+navigation_node::override_active_url($viewurl);
 
+$defaultlookahead = CALENDAR_DEFAULT_UPCOMING_LOOKAHEAD;
+if (isset($CFG->calendar_lookahead)) {
+    $defaultlookahead = intval($CFG->calendar_lookahead);
+}
+$defaultmaxevents = CALENDAR_DEFAULT_UPCOMING_MAXEVENTS;
+if (isset($CFG->calendar_maxevents)) {
+    $defaultmaxevents = intval($CFG->calendar_maxevents);
+}
 
 $prefs = new stdClass;
 $prefs->timeformat = get_user_preferences('calendar_timeformat', '');
 $prefs->startwday  = get_user_preferences('calendar_startwday', calendar_get_starting_weekday());
-$prefs->maxevents  = get_user_preferences('calendar_maxevents', CALENDAR_UPCOMING_MAXEVENTS);
-$prefs->lookahead  = get_user_preferences('calendar_lookahead', CALENDAR_UPCOMING_DAYS);
+$prefs->maxevents  = get_user_preferences('calendar_maxevents', $defaultmaxevents);
+$prefs->lookahead  = get_user_preferences('calendar_lookahead', $defaultlookahead);
 $prefs->persistflt = get_user_preferences('calendar_persistflt', 0);
 
 $form = new calendar_preferences_form();
@@ -54,7 +61,7 @@ if ($data = $form->get_data() && confirm_sesskey()) {
     }
 
     set_user_preference('calendar_persistflt', intval($data->persistflt));
-    redirect(new moodle_url('/calendar/view.php', array('course'=>$course->id)), get_string('changessaved'), 1);
+    redirect($viewurl, get_string('changessaved'), 1);
     exit;
 }
 
@@ -63,8 +70,8 @@ $strpreferences = get_string('calendarpreferences', 'calendar');
 
 $PAGE->navbar->add($strpreferences, new moodle_url('/calendar/view.php'));
 $PAGE->set_pagelayout('admin');
-$PAGE->set_title("$site->shortname: $strcalendar: $strpreferences");
-$PAGE->set_heading($COURSE->fullname);
+$PAGE->set_title("$course->shortname: $strcalendar: $strpreferences");
+$PAGE->set_heading($course->fullname);
 
 echo $OUTPUT->header();
 echo $OUTPUT->heading($strpreferences);
index 1c906d6..50a3090 100644 (file)
@@ -137,8 +137,7 @@ class core_calendar_renderer extends plugin_renderer_base {
      * @return string
      */
     public function fake_block_filters($courseid, $day, $month, $year, $view, $courses) {
-        $getvars = 'id='.$courseid.'&amp;cal_d='.$day.'&amp;cal_m='.$month.'&amp;cal_y='.$year;
-        return html_writer::tag('div', calendar_filter_controls($view, $getvars, NULL, $courses), array('class'=>'calendar_filters filters'));
+        return html_writer::tag('div', calendar_filter_controls($this->page->url), array('class'=>'calendar_filters filters'));
     }
 
     /**
@@ -216,16 +215,21 @@ class core_calendar_renderer extends plugin_renderer_base {
      * @param calendar_information $calendar
      * @return string
      */
-    public function show_day(calendar_information $calendar) {
+    public function show_day(calendar_information $calendar, moodle_url $returnurl = null) {
+
+        if ($returnurl === null) {
+            $returnurl = $this->page->url;
+        }
+
         $calendar->checkdate();
         $events = calendar_get_upcoming($calendar->courses, $calendar->groups, $calendar->users, 1, 100, $calendar->timestamp_today());
 
         $output  = html_writer::start_tag('div', array('class'=>'header'));
-        if (!isguestuser() && isloggedin() && calendar_user_can_add_event()) {
-            $output .= $this->add_event_button($calendar->courseid, $calendar->day, $calendar->month, $calendar->year);
+        if (calendar_user_can_add_event($calendar->course)) {
+            $output .= $this->add_event_button($calendar->course->id, $calendar->day, $calendar->month, $calendar->year);
         }
         //$output .= html_writer::tag('label', get_string('dayview', 'calendar'), array('for'=>'cal_course_flt_jump'));
-        $output .= $this->course_filter_selector(array('from'=>'day', 'cal_d'=>$calendar->day, 'cal_m'=>$calendar->month, 'cal_y'=>$calendar->year), get_string('dayview', 'calendar'));
+        $output .= $this->course_filter_selector($returnurl, get_string('dayview', 'calendar'));
         $output .= html_writer::end_tag('div');
         // Controls
         $output .= html_writer::tag('div', calendar_top_controls('day', array('id' => $calendar->courseid, 'd' => $calendar->day, 'm' => $calendar->month, 'y' => $calendar->year)), array('class'=>'controls'));
@@ -345,12 +349,15 @@ class core_calendar_renderer extends plugin_renderer_base {
     /**
      * Displays a month in detail
      *
-     * @global array $CALENDARDAYS
      * @param calendar_information $calendar
      * @return string
      */
-    public function show_month_detailed(calendar_information $calendar) {
-        global $CALENDARDAYS;
+    public function show_month_detailed(calendar_information $calendar, moodle_url $returnurl  = null) {
+        global $CFG;
+
+        if (empty($returnurl)) {
+            $returnurl = $this->page->url;
+        }
 
         $date = usergetdate(time());
 
@@ -396,14 +403,16 @@ class core_calendar_renderer extends plugin_renderer_base {
         calendar_events_by_day($events, $calendar->month, $calendar->year, $eventsbyday, $durationbyday, $typesbyday, $calendar->courses);
 
         $output  = html_writer::start_tag('div', array('class'=>'header'));
-        if(!isguestuser() && isloggedin() && calendar_user_can_add_event()) {
-            $output .= $this->add_event_button($calendar->courseid, null, $calendar->month, $calendar->year);
+        if (calendar_user_can_add_event($calendar->course)) {
+            $output .= $this->add_event_button($calendar->course->id, null, $calendar->month, $calendar->year);
         }
-        $output .= get_string('detailedmonthview', 'calendar').': '.$this->course_filter_selector(array('from'=>'month', 'cal_d'=>$calendar->day, 'cal_m'=>$calendar->month, 'cal_y'=>$calendar->year));
+        $output .= get_string('detailedmonthview', 'calendar').': '.$this->course_filter_selector($returnurl);
         $output .= html_writer::end_tag('div', array('class'=>'header'));
         // Controls
         $output .= html_writer::tag('div', calendar_top_controls('month', array('id' => $calendar->courseid, 'm' => $calendar->month, 'y' => $calendar->year)), array('class'=>'controls'));
 
+        $days = calendar_get_days();
+
         $table = new html_table();
         $table->attributes = array('class'=>'calendarmonth calendartable');
         $table->data = array();
@@ -414,7 +423,7 @@ class core_calendar_renderer extends plugin_renderer_base {
         for($i = $display->minwday; $i <= $display->maxwday; ++$i) {
             // This uses the % operator to get the correct weekday no matter what shift we have
             // applied to the $display->minwday : $display->maxwday range from the default 0 : 6
-            $cell = new html_table_cell(get_string($CALENDARDAYS[$i % 7], 'calendar'));
+            $cell = new html_table_cell(get_string($days[$i % 7], 'calendar'));
             $cell->header = true;
             $header->cells[] = $cell;
         }
@@ -432,6 +441,11 @@ class core_calendar_renderer extends plugin_renderer_base {
         }
 
         // Now display all the calendar
+        $weekend = CALENDAR_DEFAULT_WEEKEND;
+        if (isset($CFG->calendar_weekend)) {
+            $weekend = intval($CFG->calendar_weekend);
+        }
+
         for ($calendar->day = 1; $calendar->day <= $display->maxdays; ++$calendar->day, ++$dayweek) {
             if($dayweek > $display->maxwday) {
                 // We need to change week (table row)
@@ -447,7 +461,7 @@ class core_calendar_renderer extends plugin_renderer_base {
 
             $cellclasses = array();
 
-            if(CALENDAR_WEEKEND & (1 << ($dayweek % 7))) {
+            if ($weekend & (1 << ($dayweek % 7))) {
                 // Weekend. This is true no matter what the exact range is.
                 $cellclasses[] = 'weekend';
             }
@@ -532,16 +546,20 @@ class core_calendar_renderer extends plugin_renderer_base {
      * @param calendar_information $calendar
      * @return string
      */
-    protected function filter_selection_table(calendar_information $calendar) {
+    protected function filter_selection_table(calendar_information $calendar, moodle_url $returnurl = null) {
         global $SESSION;
 
+        if ($returnurl === null) {
+            $returnurl = $this->page->url;
+        }
+
         $output  = html_writer::start_tag('div', array('class'=>'filters'));
         $output .= html_writer::start_tag('table');
         $output .= html_writer::start_tag('tr');
 
         // Global events
-        $link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showglobal', 'from'=>'month', 'cal_d'=>$calendar->day, 'cal_m'=>$calendar->month, 'cal_y'=>$calendar->year));
-        if($SESSION->cal_show_global) {
+        $link = new moodle_url(CALENDAR_URL.'set.php', array('var' => 'showglobal', 'return' => $returnurl));
+        if (calendar_show_event_type(CALENDAR_EVENT_GLOBAL)) {
             $output .= html_writer::tag('td', '', array('class'=>'calendar_event_global', 'style'=>'width:8px;'));
             $output .= html_writer::tag('td', html_writer::tag('strong', get_string('globalevents', 'calendar')).' '.get_string('shown', 'calendar').' ('.html_writer::link($link, get_string('clickhide', 'calendar')).')');
         } else {
@@ -550,8 +568,8 @@ class core_calendar_renderer extends plugin_renderer_base {
         }
 
         // Course events
-        $link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showcourses', 'from'=>'month', 'cal_d'=>$calendar->day, 'cal_m'=>$calendar->month, 'cal_y'=>$calendar->year));
-        if(!empty($SESSION->cal_show_course)) {
+        $link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showcourses', 'return' => $returnurl));
+        if (calendar_show_event_type(CALENDAR_EVENT_COURSE)) {
             $output .= html_writer::tag('td', '', array('class'=>'calendar_event_course', 'style'=>'width:8px;'));
             $output .= html_writer::tag('td', html_writer::tag('strong', get_string('courseevents', 'calendar')).' '.get_string('shown', 'calendar').' ('.html_writer::link($link, get_string('clickhide', 'calendar')).')');
         } else {
@@ -563,8 +581,8 @@ class core_calendar_renderer extends plugin_renderer_base {
         if(isloggedin() && !isguestuser()) {
             $output .= html_writer::start_tag('tr');
             // Group events
-            $link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showgroups', 'from'=>'month', 'cal_d'=>$calendar->day, 'cal_m'=>$calendar->month, 'cal_y'=>$calendar->year));
-            if($SESSION->cal_show_groups) {
+            $link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showgroups', 'return' => $returnurl));
+            if (calendar_show_event_type(CALENDAR_EVENT_GROUP)) {
                 $output .= html_writer::tag('td', '', array('class'=>'calendar_event_group', 'style'=>'width:8px;'));
                 $output .= html_writer::tag('td', html_writer::tag('strong', get_string('groupevents', 'calendar')).' '.get_string('shown', 'calendar').' ('.html_writer::link($link, get_string('clickhide', 'calendar')).')');
             } else {
@@ -572,8 +590,8 @@ class core_calendar_renderer extends plugin_renderer_base {
                 $output .= html_writer::tag('td', html_writer::tag('strong', get_string('groupevents', 'calendar')).' '.get_string('hidden', 'calendar').' ('.html_writer::link($link, get_string('clickshow', 'calendar')).')');
             }
             // User events
-            $link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showuser', 'from'=>'month', 'cal_d'=>$calendar->day, 'cal_m'=>$calendar->month, 'cal_y'=>$calendar->year));
-            if($SESSION->cal_show_user) {
+            $link = new moodle_url(CALENDAR_URL.'set.php', array('var'=>'showuser', 'return' => $returnurl));
+            if (calendar_show_event_type(CALENDAR_EVENT_USER)) {
                 $output .= html_writer::tag('td', '', array('class'=>'calendar_event_user', 'style'=>'width:8px;'));
                 $output .= html_writer::tag('td', html_writer::tag('strong', get_string('userevents', 'calendar')).' '.get_string('shown', 'calendar').' ('.html_writer::link($link, get_string('clickhide', 'calendar')).')');
             } else {
@@ -595,15 +613,20 @@ class core_calendar_renderer extends plugin_renderer_base {
      * @param int $maxevents
      * @return string
      */
-    public function show_upcoming_events(calendar_information $calendar, $futuredays, $maxevents) {
+    public function show_upcoming_events(calendar_information $calendar, $futuredays, $maxevents, moodle_url $returnurl = null) {
+
+        if ($returnurl === null) {
+            $returnurl = $this->page->url;
+        }
+
         $events = calendar_get_upcoming($calendar->courses, $calendar->groups, $calendar->users, $futuredays, $maxevents);
 
         $output  = html_writer::start_tag('div', array('class'=>'header'));
-        if (!isguestuser() && isloggedin() && calendar_user_can_add_event()) {
-            $output .= $this->add_event_button($calendar->courseid);
+        if (calendar_user_can_add_event($calendar->course)) {
+            $output .= $this->add_event_button($calendar->course->id);
         }
         $output .= html_writer::tag('label', get_string('upcomingevents', 'calendar'), array('for'=>'cal_course_flt_jump'));
-        $output .= $this->course_filter_selector(array('from'=>'upcoming'));
+        $output .= $this->course_filter_selector($returnurl);
         $output .= html_writer::end_tag('div');
 
         if ($events) {
@@ -629,7 +652,7 @@ class core_calendar_renderer extends plugin_renderer_base {
      * @param array $getvars
      * @return string
      */
-    protected function course_filter_selector(array $getvars = array(), $label=null) {
+    protected function course_filter_selector(moodle_url $returnurl, $label=null) {
         global $USER, $SESSION, $CFG;
 
         if (!isloggedin() or isguestuser()) {
@@ -650,13 +673,12 @@ class core_calendar_renderer extends plugin_renderer_base {
             $courseoptions[$course->id] = format_string($course->shortname);
         }
 
-        if (is_numeric($SESSION->cal_courses_shown)) {
-            $selected = $SESSION->cal_courses_shown;
+        if ($this->page->course->id !== SITEID) {
+            $selected = $this->page->course->id;
         } else {
             $selected = '';
         }
-        $getvars['var'] = 'setcourse';
-        $select = new single_select(new moodle_url(CALENDAR_URL.'set.php', $getvars), 'id', $courseoptions, $selected, null);
+        $select = new single_select(new moodle_url(CALENDAR_URL.'set.php', array('return' => $returnurl, 'var' => 'setcourse')), 'id', $courseoptions, $selected, null);
         $select->class = 'cal_courses_flt';
         if ($label !== null) {
             $select->label = $label;
index 039139e..020a636 100644 (file)
 require_once('../config.php');
 require_once($CFG->dirroot.'/calendar/lib.php');
 
-$from = required_param('from', PARAM_ALPHA);
+$return = required_param('return', PARAM_URL);
 $var = required_param('var', PARAM_ALPHA);
-$id = optional_param('id', 0, PARAM_INT);
-$cal_d = optional_param('cal_d', 0, PARAM_INT);
-$cal_m = optional_param('cal_m', 0, PARAM_INT);
-$cal_y = optional_param('cal_y', 0, PARAM_INT);
-$action = optional_param('action', '', PARAM_ALPHA);
-$type = optional_param('type', '', PARAM_ALPHA);
 
-$url = new moodle_url('/calendar/set.php', array('from'=>$from,'var'=>$var));
-if ($id !== 0) {
-    $url->param('id', $id);
-}
-if ($cal_d !== 0) {
-    $url->param('cal_d', $cal_d);
-}
-if ($cal_m !== 0) {
-    $url->param('cal_m', $cal_m);
-}
-if ($cal_y !== 0) {
-    $url->param('cal_y', $cal_y);
-}
-if ($action !== 0) {
-    $url->param('action', $action);
-}
-if ($type !== 0) {
-    $url->param('type', $type);
-}
+$url = new moodle_url('/calendar/set.php', array('return'=>$return,'var'=>$var));
 $PAGE->set_url($url);
 $PAGE->set_context(get_context_instance(CONTEXT_SYSTEM)); //TODO: wrong
 
-// Initialize the session variables
-calendar_session_vars();
-
-// Ensure course id passed if relevant
-// Required due to changes in view/lib.php mainly (calendar_session_vars())
-$courseid = '';
-if (!empty($id)) {
-    $courseid = '&course='.$id;
-}
-
 switch($var) {
-    case 'setuser':
-        // Not implemented yet (or possibly at all)
-    break;
-    case 'setcourse':
-        $id = intval($id);
-        if($id == 0) {
-            $SESSION->cal_courses_shown = array();
-            calendar_set_referring_course(0);
-        }
-        else if($id == 1) {
-            $SESSION->cal_courses_shown = calendar_get_default_courses(true);
-            calendar_set_referring_course(0);
-        }
-        else {
-            if($DB->get_record('course', array('id'=>$id)) === false) {
-                // There is no such course
-                $SESSION->cal_courses_shown = array();
-                calendar_set_referring_course(0);
-            }
-            else {
-                calendar_set_referring_course($id);
-                $SESSION->cal_courses_shown = $id;
-            }
-        }
-    break;
     case 'showgroups':
-        $SESSION->cal_show_groups = !$SESSION->cal_show_groups;
-        set_user_preference('calendar_savedflt', calendar_get_filters_status());
-    break;
+        calendar_set_event_type_display(CALENDAR_EVENT_GROUP);
+        break;
     case 'showcourses':
-        $SESSION->cal_show_course = !$SESSION->cal_show_course;
-        set_user_preference('calendar_savedflt', calendar_get_filters_status());
-    break;
+        calendar_set_event_type_display(CALENDAR_EVENT_COURSE);
+        break;
     case 'showglobal':
-        $SESSION->cal_show_global = !$SESSION->cal_show_global;
-        set_user_preference('calendar_savedflt', calendar_get_filters_status());
-    break;
+        calendar_set_event_type_display(CALENDAR_EVENT_GLOBAL);
+        break;
     case 'showuser':
-        $SESSION->cal_show_user = !$SESSION->cal_show_user;
-        set_user_preference('calendar_savedflt', calendar_get_filters_status());
-    break;
+        calendar_set_event_type_display(CALENDAR_EVENT_USER);
+        break;
 }
 
-switch($from) {
-    case 'event':
-        redirect(CALENDAR_URL.'event.php?action='.$action.'&amp;type='.$type.'&amp;id='.intval($id));
-    break;
-    case 'month':
-        redirect(CALENDAR_URL.'view.php?view=month'.$courseid.'&cal_d='.$cal_d.'&cal_m='.$cal_m.'&cal_y='.$cal_y);
-    break;
-    case 'upcoming':
-        redirect(CALENDAR_URL.'view.php?view=upcoming'.$courseid);
-    break;
-    case 'day':
-        redirect(CALENDAR_URL.'view.php?view=day'.$courseid.'&cal_d='.$cal_d.'&cal_m='.$cal_m.'&cal_y='.$cal_y);
-    break;
-    case 'course':
-        redirect($CFG->wwwroot.'/course/view.php?id='.intval($id));
-    break;
-    default:
-
-}
\ No newline at end of file
+redirect($return);
\ No newline at end of file
index a1a06be..3b4c9b9 100644 (file)
@@ -44,16 +44,14 @@ require_once('../config.php');
 require_once($CFG->dirroot.'/course/lib.php');
 require_once($CFG->dirroot.'/calendar/lib.php');
 
-$courseid = optional_param('course', 0, PARAM_INT);
+$courseid = optional_param('course', SITEID, PARAM_INT);
 $view = optional_param('view', 'upcoming', PARAM_ALPHA);
 $day  = optional_param('cal_d', 0, PARAM_INT);
 $mon  = optional_param('cal_m', 0, PARAM_INT);
 $yr   = optional_param('cal_y', 0, PARAM_INT);
 
-$site = get_site();
-
 $url = new moodle_url('/calendar/view.php');
-if ($courseid !== 0) {
+if ($courseid != SITEID) {
     $url->param('course', $courseid);
 }
 if ($view !== 'upcoming') {
@@ -70,34 +68,27 @@ if ($yr !== 0) {
 }
 $PAGE->set_url($url);
 
-//TODO: the courseid handling in /calendar/ is a bloody mess!!!
-
-if ($courseid && $courseid != SITEID) {
-    require_login($courseid);
-} else if ($CFG->forcelogin) {
-    $PAGE->set_context(get_context_instance(CONTEXT_SYSTEM)); //TODO: wrong
-    require_login();
+if ($courseid != SITEID && !empty($courseid)) {
+    $course = $DB->get_record('course', array('id' => $courseid));
+    $courses = array($course->id => $course);
+    $issite = false;
+    navigation_node::override_active_url(new moodle_url('/course/view.php', array('id' => $course->id)));
 } else {
-    $PAGE->set_context(get_context_instance(CONTEXT_SYSTEM)); //TODO: wrong
+    $course = get_site();
+    $courses = calendar_get_default_courses();
+    $issite = true;
 }
+require_course_login($course);
 
 $calendar = new calendar_information($day, $mon, $yr);
-$calendar->courseid = $courseid;
-
-// Initialize the session variables
-calendar_session_vars();
+$calendar->prepare_for_view($course, $courses);
 
-//add_to_log($course->id, "course", "view", "view.php?id=$course->id", "$course->id");
 $now = usergetdate(time());
 $pagetitle = '';
 
 $strcalendar = get_string('calendar', 'calendar');
 
-$link = calendar_get_link_href(new moodle_url(CALENDAR_URL.'view.php', array('view'=>'upcoming', 'course'=>$courseid)),
-                               $now['mday'], $now['mon'], $now['year']);
-$PAGE->navbar->add($strcalendar, $link);
-
-if(!checkdate($mon, $day, $yr)) {
+if (!checkdate($mon, $day, $yr)) {
     $day = intval($now['mday']);
     $mon = intval($now['mon']);
     $yr = intval($now['year']);
@@ -117,47 +108,12 @@ switch($view) {
         $pagetitle = get_string('upcomingevents', 'calendar');
     break;
 }
-// If a course has been supplied in the URL, change the filters to show that one
-if (!empty($courseid)) {
-    if ($course = $DB->get_record('course', array('id'=>$courseid))) {
-        if ($course->id == SITEID) {
-            // If coming from the home page, show all courses
-            $SESSION->cal_courses_shown = calendar_get_default_courses(true);
-            calendar_set_referring_course(0);
-
-        } else {
-            // Otherwise show just this one
-            $SESSION->cal_courses_shown = $course->id;
-            calendar_set_referring_course($SESSION->cal_courses_shown);
-        }
-    }
-} else {
-    $course = null;
-}
-if (!isloggedin() or isguestuser()) {
-    $defaultcourses = calendar_get_default_courses();
-    calendar_set_filters($calendar->courses, $calendar->groups, $calendar->users, $defaultcourses, $defaultcourses);
-} else {
-    calendar_set_filters($calendar->courses, $calendar->groups, $calendar->users);
-}
-// Let's see if we are supposed to provide a referring course link
-// but NOT for the "main page" course
-if ($SESSION->cal_course_referer != SITEID &&
-   ($shortname = $DB->get_field('course', 'shortname', array('id'=>$SESSION->cal_course_referer))) !== false) {
-    require_login(); //TODO: very wrong!!
-    if (empty($course)) {
-        $course = $DB->get_record('course', array('id'=>$SESSION->cal_course_referer)); // Useful to have around
-    }
-}
-
-$strcalendar = get_string('calendar', 'calendar');
-$prefsbutton = calendar_preferences_button();
 
 // Print title and header
-$PAGE->set_title("$site->shortname: $strcalendar: $pagetitle");
-$PAGE->set_heading($COURSE->fullname);
-$PAGE->set_button($prefsbutton);
 $PAGE->set_pagelayout('standard');
+$PAGE->set_title("$course->shortname: $strcalendar: $pagetitle");
+$PAGE->set_heading($COURSE->fullname);
+$PAGE->set_button(calendar_preferences_button($course));
 
 $renderer = $PAGE->get_renderer('core_calendar');
 $calendar->add_sidecalendar_blocks($renderer, true, $view);
@@ -174,7 +130,18 @@ switch($view) {
         echo $renderer->show_month_detailed($calendar);
     break;
     case 'upcoming':
-        echo $renderer->show_upcoming_events($calendar, get_user_preferences('calendar_lookahead', CALENDAR_UPCOMING_DAYS), get_user_preferences('calendar_maxevents', CALENDAR_UPCOMING_MAXEVENTS));
+        $defaultlookahead = CALENDAR_DEFAULT_UPCOMING_LOOKAHEAD;
+        if (isset($CFG->calendar_lookahead)) {
+            $defaultlookahead = intval($CFG->calendar_lookahead);
+        }
+        $lookahead = get_user_preferences('calendar_lookahead', $defaultlookahead);
+
+        $defaultmaxevents = CALENDAR_DEFAULT_UPCOMING_MAXEVENTS;
+        if (isset($CFG->calendar_maxevents)) {
+            $defaultmaxevents = intval($CFG->calendar_maxevents);
+        }
+        $maxevents = get_user_preferences('calendar_maxevents', $defaultmaxevents);
+        echo $renderer->show_upcoming_events($calendar, $lookahead, $maxevents);
     break;
 }
 
@@ -189,6 +156,7 @@ if (!empty($CFG->enablecalendarexport)) {
         echo html_writer::tag('a', $icon, array('href'=>$link));
     }
 }
+
 echo $OUTPUT->container_end();
 echo html_writer::end_tag('div');
 echo $renderer->complete_layout();
index 1a9dbd9..8517148 100644 (file)
@@ -4218,7 +4218,7 @@ class course_request {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function course_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function course_page_type_list($pagetype, $parentcontext, $currentcontext) {
     // if above course context ,display all course fomats
     list($currentcontext, $course, $cm) = get_context_info_array($currentcontext->id);
     if ($course->id == SITEID) {
@@ -4230,4 +4230,4 @@ function course_pagetypelist($pagetype, $parentcontext, $currentcontext) {
             'mod-*'=>get_string('page-mod-x', 'pagetype')
         );
     }
-}
+}
\ No newline at end of file
index 3e67898..2ec123a 100644 (file)
@@ -2,4 +2,5 @@
 
 $string['completion:view'] = 'View course completion report';
 $string['completiondate']='Completion date';
+$string['pluginpagetype'] = 'Completion course report';
 $string['pluginname']='Course completion';
index a84f3a2..7bf087e 100644 (file)
@@ -44,3 +44,18 @@ function completion_report_extend_navigation($navigation, $course, $context) {
         }
     }
 }
+
+/**
+ * Return a list of page types
+ * @param string $pagetype current page type
+ * @param stdClass $parentcontext Block's parent context
+ * @param stdClass $currentcontext Current context of block
+ */
+function completion_page_type_list($pagetype, $parentcontext, $currentcontext) {
+    $array = array(
+        '*' => get_string('page-x', 'pagetype'),
+        'course-report-*' => get_string('page-course-report-x', 'pagetype'),
+        'course-report-completion-*' => get_string('pluginpagetype',  'coursereport_completion')
+    );
+    return $array;
+}
diff --git a/course/report/lib.php b/course/report/lib.php
new file mode 100644 (file)
index 0000000..3ed43f7
--- /dev/null
@@ -0,0 +1,38 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * This file contains functions used by course reports
+ *
+ * @since 2.1
+ * @package course-report
+ * @copyright 2011 Andrew Davis
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+/**
+ * Return a list of page types
+ * @param string $pagetype current page type
+ * @param stdClass $parentcontext Block's parent context
+ * @param stdClass $currentcontext Current context of block
+ */
+function coursereport_page_type_list($pagetype, $parentcontext, $currentcontext) {
+    $array = array(
+        '*' => get_string('page-x', 'pagetype'),
+        'course-report-*' => get_string('page-course-report-x', 'pagetype')
+    );
+    return $array;
+}
\ No newline at end of file
index dc37408..431e260 100644 (file)
@@ -27,4 +27,5 @@ $string['loglive'] = 'Live logs';
 $string['log:view'] = 'View course logs';
 $string['log:viewlive'] = 'View live logs';
 $string['log:viewtoday'] = 'View today\'s logs';
+$string['pluginpagetype'] = 'Log course report';
 $string['pluginname'] = 'Logs';
index 96cbdc7..de27692 100644 (file)
@@ -537,3 +537,18 @@ function log_report_extend_navigation($navigation, $course, $context) {
         $navigation->add(get_string('pluginname', 'coursereport_log'), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/report', ''));
     }
 }
+
+/**
+ * Return a list of page types
+ * @param string $pagetype current page type
+ * @param stdClass $parentcontext Block's parent context
+ * @param stdClass $currentcontext Current context of block
+ */
+function log_page_type_list($pagetype, $parentcontext, $currentcontext) {
+    $array = array(
+        '*' => get_string('page-x', 'pagetype'),
+        'course-report-*' => get_string('page-course-report-x', 'pagetype'),
+        'course-report-log-*' => get_string('pluginpagetype',  'coursereport_log')
+    );
+    return $array;
+}
\ No newline at end of file
index ad4ef64..dc1dd10 100644 (file)
             $reportrow->cells[] = $numviewscell;
 
             if ($CFG->useblogassociations) {
+                require_once($CFG->dirroot.'/blog/lib.php');
                 $blogcell = new html_table_cell();
                 $blogcell->attributes['class'] = 'blog';
                 if ($blogcount = blog_get_associated_count($course->id, $cm->id)) {
index eaf1886..6bce7b8 100644 (file)
@@ -24,4 +24,5 @@
  */
 
 $string['outline:view'] = 'View course activity report';
+$string['pluginpagetype'] = 'Course activity report';
 $string['pluginname'] = 'Course activity';
index c020dcc..f3632b3 100644 (file)
@@ -37,4 +37,19 @@ function outline_report_extend_navigation($navigation, $course, $context) {
         $url = new moodle_url('/course/report/outline/index.php', array('id'=>$course->id));
         $navigation->add(get_string( 'activityreport' ), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/report', ''));
     }
+}
+
+/**
+ * Return a list of page types
+ * @param string $pagetype current page type
+ * @param stdClass $parentcontext Block's parent context
+ * @param stdClass $currentcontext Current context of block
+ */
+function outline_page_type_list($pagetype, $parentcontext, $currentcontext) {
+    $array = array(
+        '*' => get_string('page-x', 'pagetype'),
+        'course-report-*' => get_string('page-course-report-x', 'pagetype'),
+        'course-report-outline-*' => get_string('pluginpagetype',  'coursereport_outline')
+    );
+    return $array;
 }
\ No newline at end of file
index 82e9864..16e5eaa 100644 (file)
@@ -24,4 +24,5 @@
  */
 
 $string['participation:view'] = 'View course participation report';
+$string['pluginpagetype'] = 'Participation course report';
 $string['pluginname'] = 'Course participation';
index 7071876..62429c9 100644 (file)
@@ -37,4 +37,19 @@ function participation_report_extend_navigation($navigation, $course, $context)
         $url = new moodle_url('/course/report/participation/index.php', array('id'=>$course->id));
         $navigation->add(get_string('participationreport'), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/report', ''));
     }
+}
+
+/**
+ * Return a list of page types
+ * @param string $pagetype current page type
+ * @param stdClass $parentcontext Block's parent context
+ * @param stdClass $currentcontext Current context of block
+ */
+function participation_page_type_list($pagetype, $parentcontext, $currentcontext) {
+    $array = array(
+        '*' => get_string('page-x', 'pagetype'),
+        'course-report-*' => get_string('page-course-report-x', 'pagetype'),
+        'course-report-participation-*' => get_string('pluginpagetype',  'coursereport_participation')
+    );
+    return $array;
 }
\ No newline at end of file
index 7cb9005..dd27c66 100644 (file)
@@ -24,4 +24,5 @@
  */
 
 $string['pluginname'] = 'Activity completion';
+$string['pluginpagetype'] = 'Progress course report';
 $string['progress:view'] = 'View activity completion reports';
index f4c74f6..23a9686 100644 (file)
@@ -49,3 +49,18 @@ function progress_report_extend_navigation($navigation, $course, $context) {
         $navigation->add(get_string('pluginname','coursereport_progress'), $url, navigation_node::TYPE_SETTING, null, null, new pix_icon('i/report', ''));
     }
 }
+
+/**
+ * Return a list of page types
+ * @param string $pagetype current page type
+ * @param stdClass $parentcontext Block's parent context
+ * @param stdClass $currentcontext Current context of block
+ */
+function progress_page_type_list($pagetype, $parentcontext, $currentcontext) {
+    $array = array(
+        '*' => get_string('page-x', 'pagetype'),
+        'course-report-*' => get_string('page-course-report-x', 'pagetype'),
+        'course-report-progress-*' => get_string('pluginpagetype',  'coursereport_progress')
+    );
+    return $array;
+}
\ No newline at end of file
index d4491a9..38815c8 100644 (file)
@@ -24,4 +24,5 @@
  */
 
 $string['pluginname'] = 'Course statistics';
+$string['pluginpagetype'] = 'Statistics course report';
 $string['stats:view'] = 'View course statistics report';
index ed31e78..220e8df 100644 (file)
@@ -91,3 +91,18 @@ function stats_report_extend_navigation($navigation, $course, $context) {
         }
     }
 }
+
+/**
+ * Return a list of page types
+ * @param string $pagetype current page type
+ * @param stdClass $parentcontext Block's parent context
+ * @param stdClass $currentcontext Current context of block
+ */
+function stats_page_type_list($pagetype, $parentcontext, $currentcontext) {
+    $array = array(
+        '*' => get_string('page-x', 'pagetype'),
+        'course-report-*' => get_string('page-course-report-x', 'pagetype'),
+        'course-report-stats-*' => get_string('pluginpagetype',  'coursereport_stats')
+    );
+    return $array;
+}
\ No newline at end of file
diff --git a/lang/en/mathslib.php b/lang/en/mathslib.php
new file mode 100644 (file)
index 0000000..ab55cf0
--- /dev/null
@@ -0,0 +1,42 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Strings for component 'mathslib', language 'en', branch 'MOODLE_19_STABLE'
+ *
+ * @package   mathslib
+ * @copyright 1999 onwards Martin Dougiamas  {@link http://moodle.com}
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+$string['anunexpectederroroccured'] = 'an unexpected error occured';
+$string['cannotassigntoconstant'] = 'cannot assign to constant \'{$a}\'';
+$string['cannotredefinebuiltinfunction'] = 'cannot redefine built-in function \'{$a}()\'';
+$string['divisionbyzero'] = 'division by zero';
+$string['expectingaclosingbracket'] = 'expecting a closing bracket';
+$string['illegalcharactergeneral'] = 'illegal character \'{$a}\'';
+$string['illegalcharacterunderscore'] = 'illegal character \'_\'';
+$string['implicitmultiplicationnotallowed'] = 'expecting operator, implicit multiplication not allowed.';
+$string['internalerror'] = 'internal error';
+$string['operatorlacksoperand'] = 'operator \'{$a}\' lacks operand';
+$string['undefinedvariable'] = 'undefined variable \'{$a}\'';
+$string['undefinedvariableinfunctiondefinition'] = 'undefined variable \'{$a}\' in function definition';
+$string['unexpectedclosingbracket'] = 'unexpected closing bracket';
+$string['unexpectedcomma'] = 'unexpected comma';
+$string['unexpectedoperator'] = 'unexpected operator \'{$a}\'';
+$string['wrongnumberofarguments'] = 'wrong number of arguments ({$a->given} given, {$a->expected} expected)';
+
index bc540f0..7a073f4 100644 (file)
@@ -25,6 +25,7 @@
 
 $string['page-course-view-x'] = 'Any type of course main page';
 $string['page-course-x'] = 'Any course page';
+$string['page-course-report-x'] = 'Any course report';
 $string['page-mod-x'] = 'Any activity module page';
 $string['page-mod-x-view'] = 'Any main activity module page';
 $string['page-my-index'] = 'My home page';
index da83c56..2f32d8a 100644 (file)
@@ -2935,7 +2935,6 @@ class admin_setting_special_adminseesall extends admin_setting_configcheckbox {
      */
     public function write_setting($data) {
         global $SESSION;
-        unset($SESSION->cal_courses_shown);
         return parent::write_setting($data);
     }
 }
index 608a3d5..991b34d 100644 (file)
@@ -1217,13 +1217,14 @@ class block_manager {
                 // If the block wants to be system-wide, then explicitly set that
                 if ($data->bui_contexts == BUI_CONTEXTS_ENTIRE_SITE) {   // Only possible on a frontpage or system page
                     $bi->parentcontextid = $systemcontext->id;
-                    $bi->showinsubcontexts = 1;
+                    $bi->showinsubcontexts = BUI_CONTEXTS_CURRENT_SUBS; //show in current and sub contexts
+                    $bi->pagetypepattern = '*';
 
                 } else { // The block doesn't want to be system-wide, so let's ensure that
                     if ($parentcontext->id == $systemcontext->id) {  // We need to move it to the front page
                         $frontpagecontext = get_context_instance(CONTEXT_COURSE, SITEID);
                         $bi->parentcontextid = $frontpagecontext->id;
-                        $bi->pagetypepattern = '*';  // Just in case
+                        $bi->pagetypepattern = 'site-index';
                     }
                 }
             }
@@ -1563,34 +1564,72 @@ function generate_page_type_patterns($pagetype, $parentcontext = null, $currentc
 
     $bits = explode('-', $pagetype);
 
-    $component = clean_param(reset($bits), PARAM_ALPHANUMEXT);
-    $function = 'default_pagetypelist';
-
     $core = get_core_subsystems();
     $plugins = get_plugin_types();
 
-    // First check to see if the initial component is a core component
-    // if its not check to see if it is a plugin component.
-    if (array_key_exists($component, $core) && !empty($core[$component])) {
-        $libfile = $CFG->dirroot.'/'.$core[$component].'/lib.php';
-        if (file_exists($libfile)) {
-            require_once($libfile);
-            if (function_exists($component.'_pagetypelist')) {
-                $function = $component.'_pagetypelist';
+    //progressively strip pieces off the page type looking for a match
+    $componentarray = null;
+    for ($i = count($bits); $i > 0; $i--) {
+        $possiblecomponentarray = array_slice($bits, 0, $i);
+        $possiblecomponent = implode('', $possiblecomponentarray);
+
+        // Check to see if the component is a core component
+        if (array_key_exists($possiblecomponent, $core) && !empty($core[$possiblecomponent])) {
+            $libfile = $CFG->dirroot.'/'.$core[$possiblecomponent].'/lib.php';
+            if (file_exists($libfile)) {
+                require_once($libfile);
+                $function = $possiblecomponent.'_page_type_list';
+                if (function_exists($function)) {
+                    if ($patterns = $function($pagetype, $parentcontext, $currentcontext)) {
+                        break;
+                    }
+                }
             }
         }
-    } else if (array_key_exists($component, $plugins) && !empty($plugins[$component])) {
-        $function = 'plugin_pagetypelist';
-        if (function_exists($component.'_pagetypelist')) {
-            $function = $component.'_pagetypelist';
+
+        //check the plugin directory and look for a callback
+        if (array_key_exists($possiblecomponent, $plugins) && !empty($plugins[$possiblecomponent])) {
+
+            //We've found a plugin type. Look for a plugin name by getting the next section of page type
+            if (count($bits) > $i) {
+                $pluginname = $bits[$i];
+                $directory = get_plugin_directory($possiblecomponent, $pluginname);
+                if (!empty($directory)){
+                    $libfile = $directory.'/lib.php';
+                    if (file_exists($libfile)) {
+                        require_once($libfile);
+                        $function = $pluginname.'_page_type_list';
+                        if (function_exists($function)) {
+                            if ($patterns = $function($pagetype, $parentcontext, $currentcontext)) {
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+
+            //we'll only get to here if we still don't have any patterns
+            //the plugin type may have a callback
+            $directory = get_plugin_directory($possiblecomponent, null);
+            if (!empty($directory)){
+                $libfile = $directory.'/lib.php';
+                if (file_exists($libfile)) {
+                    require_once($libfile);
+                    $function = $possiblecomponent.'_page_type_list';
+                    if (function_exists($function)) {
+                        if ($patterns = $function($pagetype, $parentcontext, $currentcontext)) {
+                            break;
+                        }
+                    }
+                }
+            }
         }
     }
-    // Call the most appropriate function we could determine
-    $patterns = $function($pagetype, $parentcontext, $currentcontext);
+
     if (empty($patterns)) {
-        // If there are no patterns default to just the current pattern.
-        $patterns = array($pagetype => $pagetype);
+        $patterns = default_page_type_list($pagetype, $parentcontext, $currentcontext);
     }
+
     return $patterns;
 }
 
@@ -1602,7 +1641,7 @@ function generate_page_type_patterns($pagetype, $parentcontext = null, $currentc
  * @param stdClass $currentcontext
  * @return array
  */
-function default_pagetypelist($pagetype, $parentcontext = null, $currentcontext = null) {
+function default_page_type_list($pagetype, $parentcontext = null, $currentcontext = null) {
     // Generate page type patterns based on current page type if
     // callbacks haven't been defined
     $patterns = array($pagetype => $pagetype);
@@ -1622,40 +1661,6 @@ function default_pagetypelist($pagetype, $parentcontext = null, $currentcontext
     return $patterns;
 }
 
-/**
- * Generates a page type list for plugins
- *
- * @param string $pagetype
- * @param stdClass $parentcontext
- * @param stdClass $currentcontext
- * @return array
- */
-function plugin_pagetypelist($pagetype, $parentcontext = null, $currentcontext = null) {
-    global $CFG;
-
-    // for modules
-    $bits = explode('-', $pagetype);
-    $plugintype = $bits[0];
-    $pluginname = $bits[1];
-    $directory = get_plugin_directory($plugintype, $pluginname);
-    if (empty($directory)) {
-        return array();
-    }
-    $libfile = $directory.'/lib.php';
-    require_once($libfile);
-    $function = $pluginname.'_pagetypelist';
-    if (!function_exists($function)) {
-        return array();
-    }
-    $patterns = $function($pagetype, $parentcontext, $currentcontext);
-    if ($parentcontext->contextlevel == CONTEXT_COURSE) {
-        // including course page type
-        require_once("$CFG->dirroot/course/lib.php");
-        $patterns = array_merge(course_pagetypelist($pagetype, $parentcontext, $currentcontext), $patterns);
-    }
-    return $patterns;
-}
-
 /**
  * Generates the page type list for the my moodle page
  *
@@ -1664,7 +1669,7 @@ function plugin_pagetypelist($pagetype, $parentcontext = null, $currentcontext =
  * @param stdClass $currentcontext
  * @return array
  */
-function my_pagetypelist($pagetype, $parentcontext = null, $currentcontext = null) {
+function my_page_type_list($pagetype, $parentcontext = null, $currentcontext = null) {
     return array('my-index' => 'my-index');
 }
 
@@ -1677,8 +1682,8 @@ function my_pagetypelist($pagetype, $parentcontext = null, $currentcontext = nul
  * @param stdClass $currentcontext
  * @return array
  */
-function mod_pagetypelist($pagetype, $parentcontext = null, $currentcontext = null) {
-    $patterns = plugin_pagetypelist($pagetype, $parentcontext, $currentcontext);
+function mod_page_type_list($pagetype, $parentcontext = null, $currentcontext = null) {
+    $patterns = plugin_page_type_list($pagetype, $parentcontext, $currentcontext);
     if (empty($patterns)) {
         // if modules don't have callbacks
         // generate two default page type patterns for modules only
index 53c1309..117bf9d 100644 (file)
@@ -129,6 +129,15 @@ $functions = array(
         'capabilities'=> 'moodle/user:viewdetails, moodle/user:viewhiddendetails, moodle/course:useremail, moodle/user:update',
     ),
 
+    'moodle_user_get_users_by_courseid' => array(
+        'classname'   => 'moodle_user_external',
+        'methodname'  => 'get_users_by_courseid',
+        'classpath'   => 'user/externallib.php',
+        'description' => 'Get enrolled users by course id.',
+        'type'        => 'read',
+        'capabilities'=> 'moodle/user:viewdetails, moodle/user:viewhiddendetails, moodle/course:useremail, moodle/user:update, moodle/site:accessallgroups',
+    ),
+
     'moodle_user_get_course_participants_by_id' => array(
         'classname'   => 'moodle_user_external',
         'methodname'  => 'get_course_participants_by_id',
@@ -217,11 +226,11 @@ $functions = array(
 
     // === message related functions ===
 
-    'moodle_message_send_messages' => array(
+    'moodle_message_send_instantmessages' => array(
         'classname'   => 'moodle_message_external',
-        'methodname'  => 'send_messages',
+        'methodname'  => 'send_instantmessages',
         'classpath'   => 'message/externallib.php',
-        'description' => 'Send messages',
+        'description' => 'Send instant messages',
         'type'        => 'write',
         'capabilities'=> 'moodle/site:sendmessage',
     ),
@@ -258,7 +267,8 @@ $services = array(
             'moodle_webservice_get_siteinfo',
             'moodle_notes_create_notes',
             'moodle_user_get_course_participants_by_id',
-            'moodle_message_send_messages'),
+            'moodle_user_get_users_by_courseid',
+            'moodle_message_send_instantmessages'),
         'enabled' => 0,
         'restrictedusers' => 0,
         'shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE
index b12db58..271fb12 100644 (file)
@@ -6191,6 +6191,13 @@ WHERE gradeitemid IS NOT NULL AND grademax IS NOT NULL");
                 )
             ");
 
+            // It seems that it is possible, in old versions of Moodle, for a
+            // quiz_attempt to be deleted while the question_attempt remains.
+            // In that situation we still get NULLs left in the table, which
+            // causes the upgrade to break at the next step. To avoid breakage,
+            // without risking dataloss, we just replace all NULLs with 0 here.
+            $DB->set_field_select('question_usages', 'contextid', 0, 'contextid IS NULL');
+
             // Then make it NOT NULL.
             $field = new xmldb_field('contextid');
             $field->set_attributes(XMLDB_TYPE_INTEGER, '10', XMLDB_UNSIGNED,
index 9bddc50..0597f18 100644 (file)
@@ -94,6 +94,9 @@ LICENSE
 
 class EvalMath {
 
+    /** @var string Pattern used for a valid function or variable name. Note, var and func names are case insensitive.*/
+    private static $namepat = '[a-z][a-z0-9_]*';
+
     var $suppress_errors = false;
     var $last_error = null;
 
@@ -104,14 +107,22 @@ class EvalMath {
         'sin','sinh','arcsin','asin','arcsinh','asinh',
         'cos','cosh','arccos','acos','arccosh','acosh',
         'tan','tanh','arctan','atan','arctanh','atanh',
-        'sqrt','abs','ln','log','exp');
+        'sqrt','abs','ln','log','exp','floor','ceil','round');
 
     var $fc = array( // calc functions emulation
         'average'=>array(-1), 'max'=>array(-1),  'min'=>array(-1),
         'mod'=>array(2),      'pi'=>array(0),    'power'=>array(2),
-        'round'=>array(1, 2), 'sum'=>array(-1));
+        'round'=>array(1, 2), 'sum'=>array(-1), 'rand_int'=>array(2),
+        'rand_float'=>array(0));
+
+    var $allowimplicitmultiplication;
 
-    function EvalMath() {
+    function EvalMath($allowconstants = false, $allowimplicitmultiplication = false) {
+        if ($allowconstants){
+            $this->v['pi'] = pi();
+            $this->v['e'] = exp(1);
+        }
+        $this->allowimplicitmultiplication = $allowimplicitmultiplication;
     }
 
     function e($expr) {
@@ -126,7 +137,7 @@ class EvalMath {
         // is it a variable assignment?
         if (preg_match('/^\s*([a-z][a-z0-9]*)\s*=\s*(.+)$/', $expr, $matches)) {
             if (in_array($matches[1], $this->vb)) { // make sure we're not assigning to a constant
-                return $this->trigger("cannot assign to constant '$matches[1]'");
+                return $this->trigger(get_string('cannotassigntoconstant', 'mathslib', $matches[1]));
             }
             if (($tmp = $this->pfx($this->nfx($matches[2]))) === false) return false; // get the result and make sure it's good
             $this->v[$matches[1]] = $tmp; // if so, stick it in the variable array
@@ -136,7 +147,7 @@ class EvalMath {
         } elseif (preg_match('/^\s*([a-z][a-z0-9]*)\s*\(\s*([a-z][a-z0-9]*(?:\s*,\s*[a-z][a-z0-9]*)*)\s*\)\s*=\s*(.+)$/', $expr, $matches)) {
             $fnn = $matches[1]; // get the function name
             if (in_array($matches[1], $this->fb)) { // make sure it isn't built in
-                return $this->trigger("cannot redefine built-in function '$matches[1]()'");
+                return $this->trigger(get_string('cannotredefinebuiltinfunction', 'mathslib', $matches[1]));
             }
             $args = explode(",", preg_replace("/\s+/", "", $matches[2])); // get the arguments
             if (($stack = $this->nfx($matches[3])) === false) return false; // see if it can be converted to postfix
@@ -146,7 +157,7 @@ class EvalMath {
                     if (array_key_exists($token, $this->v)) {
                         $stack[$i] = $this->v[$token];
                     } else {
-                        return $this->trigger("undefined variable '$token' in function definition");
+                        return $this->trigger(get_string('undefinedvariableinfunctiondefinition', 'mathslib', $token));
                     }
                 }
             }
@@ -169,6 +180,14 @@ class EvalMath {
         return $output;
     }
 
+    /**
+     * @param string $name
+     * @return boolean Is this a valid var or function name?
+     */
+    public static function is_valid_var_or_func_name($name){
+        return preg_match('/'.self::$namepat.'$/iA', $name);
+    }
+
     //===================== HERE BE INTERNAL METHODS ====================\\
 
     // Convert infix to postfix notation
@@ -187,7 +206,7 @@ class EvalMath {
                                // and determining when a - is a negation
 
         if (preg_match("/[^\w\s+*^\/()\.,-]/", $expr, $matches)) { // make sure the characters are all good
-            return $this->trigger("illegal character '{$matches[0]}'");
+            return $this->trigger(get_string('illegalcharactergeneral', 'mathslib', $matches[0]));
         }
 
         while(1) { // 1 Infinite Loop ;)
@@ -199,12 +218,16 @@ class EvalMath {
                 $stack->push('_'); // put a negation on the stack
                 $index++;
             } elseif ($op == '_') { // we have to explicitly deny this, because it's legal on the stack
-                return $this->trigger("illegal character '_'"); // but not in the input expression
+                return $this->trigger(get_string('illegalcharacterunderscore', 'mathslib')); // but not in the input expression
             //===============
             } elseif ((in_array($op, $ops) or $ex) and $expecting_op) { // are we putting an operator on the stack?
                 if ($ex) { // are we expecting an operator but have a number/variable/function/opening parethesis?
-                    return $this->trigger("expecting operand");
-                    //$op = '*'; $index--; // it's an implicit multiplication
+                    if (!$this->allowimplicitmultiplication){
+                        return $this->trigger(get_string('implicitmultiplicationnotallowed', 'mathslib'));
+                    } else {// it's an implicit multiplication
+                        $op = '*';
+                        $index--;
+                    }
                 }
                 // heart of the algorithm:
                 while($stack->count > 0 and ($o2 = $stack->last()) and in_array($o2, $ops) and ($ops_r[$op] ? $ops_p[$op] < $ops_p[$o2] : $ops_p[$op] <= $ops_p[$o2])) {
@@ -217,7 +240,7 @@ class EvalMath {
             //===============
             } elseif ($op == ')' and $expecting_op) { // ready to close a parenthesis?
                 while (($o2 = $stack->pop()) != '(') { // pop off the stack back to the last (
-                    if (is_null($o2)) return $this->trigger("unexpected ')'");
+                    if (is_null($o2)) return $this->trigger(get_string('unexpectedclosingbracket', 'mathslib'));
                     else $output[] = $o2;
                 }
                 if (preg_match("/^([a-z][a-z0-9]*)\($/", $stack->last(2), $matches)) { // did we just close a function?
@@ -226,30 +249,42 @@ class EvalMath {
                     $fn = $stack->pop();
                     $output[] = array('fn'=>$fn, 'fnn'=>$fnn, 'argcount'=>$arg_count); // send function to output
                     if (in_array($fnn, $this->fb)) { // check the argument count
-                        if($arg_count > 1)
-                            return $this->trigger("too many arguments ($arg_count given, 1 expected)");
+                        if($arg_count > 1) {
+                            $a= new stdClass();
+                            $a->expected = 1;
+                            $a->given = $arg_count;
+                            return $this->trigger(get_string('wrongnumberofarguments', 'mathslib', $a));
+                        }
                     } elseif (array_key_exists($fnn, $this->fc)) {
                         $counts = $this->fc[$fnn];
                         if (in_array(-1, $counts) and $arg_count > 0) {}
-                        elseif (!in_array($arg_count, $counts))
-                            return $this->trigger("wrong number of arguments ($arg_count given, " . implode('/',$this->fc[$fnn]) . " expected)");
+                        elseif (!in_array($arg_count, $counts)) {
+                            $a= new stdClass();
+                            $a->expected = implode('/',$this->fc[$fnn]);
+                            $a->given = $arg_count;
+                            return $this->trigger(get_string('wrongnumberofarguments', 'mathslib', $a));
+                        }
                     } elseif (array_key_exists($fnn, $this->f)) {
-                        if ($arg_count != count($this->f[$fnn]['args']))
-                            return $this->trigger("wrong number of arguments ($arg_count given, " . count($this->f[$fnn]['args']) . " expected)");
+                        if ($arg_count != count($this->f[$fnn]['args'])) {
+                            $a= new stdClass();
+                            $a->expected = count($this->f[$fnn]['args']);
+                            $a->given = $arg_count;
+                            return $this->trigger(get_string('wrongnumberofarguments', 'mathslib', $a));
+                        }
                     } else { // did we somehow push a non-function on the stack? this should never happen
-                        return $this->trigger("internal error");
+                        return $this->trigger(get_string('internalerror', 'mathslib'));
                     }
                 }
                 $index++;
             //===============
             } elseif ($op == ',' and $expecting_op) { // did we just finish a function argument?
                 while (($o2 = $stack->pop()) != '(') {
-                    if (is_null($o2)) return $this->trigger("unexpected ','"); // oops, never had a (
+                    if (is_null($o2)) return $this->trigger(get_string('unexpectedcomma', 'mathslib')); // oops, never had a (
                     else $output[] = $o2; // pop the argument expression stuff and push onto the output
                 }
                 // make sure there was a function
                 if (!preg_match("/^([a-z][a-z0-9]*)\($/", $stack->last(2), $matches))
-                    return $this->trigger("unexpected ','");
+                    return $this->trigger(get_string('unexpectedcomma', 'mathslib'));
                 $stack->push($stack->pop()+1); // increment the argument count
                 $stack->push('('); // put the ( back on, we'll need to pop back to it again
                 $index++;
@@ -280,29 +315,34 @@ class EvalMath {
             //===============
             } elseif ($op == ')') {
                 //it could be only custom function with no params or general error
-                if ($stack->last() != '(' or $stack->last(2) != 1) return $this->trigger("unexpected ')'");
+                if ($stack->last() != '(' or $stack->last(2) != 1) return $this->trigger(get_string('unexpectedclosingbracket', 'mathslib'));
                 if (preg_match("/^([a-z][a-z0-9]*)\($/", $stack->last(3), $matches)) { // did we just close a function?
                     $stack->pop();// (
                     $stack->pop();// 1
                     $fn = $stack->pop();
                     $fnn = $matches[1]; // get the function name
                     $counts = $this->fc[$fnn];
-                    if (!in_array(0, $counts))
-                        return $this->trigger("wrong number of arguments ($arg_count given, " . implode('/',$this->fc[$fnn]) . " expected)");
+                    if (!in_array(0, $counts)){
+                        $a= new stdClass();
+                        $a->expected = $this->fc[$fnn];
+                        $a->given = 0;
+                        return $this->trigger(get_string('wrongnumberofarguments', 'mathslib', $a));
+                    }
                     $output[] = array('fn'=>$fn, 'fnn'=>$fnn, 'argcount'=>0); // send function to output
                     $index++;
+                    $expecting_op = true;
                 } else {
-                    return $this->trigger("unexpected ')'");
+                    return $this->trigger(get_string('unexpectedclosingbracket', 'mathslib'));
                 }
             //===============
             } elseif (in_array($op, $ops) and !$expecting_op) { // miscellaneous error checking
-                return $this->trigger("unexpected operator '$op'");
+                return $this->trigger(get_string('unexpectedoperator', 'mathslib', $op));
             } else { // I don't even want to know what you did to get here
-                return $this->trigger("an unexpected error occured");
+                return $this->trigger(get_string('anunexpectederroroccured', 'mathslib'));
             }
             if ($index == strlen($expr)) {
                 if (in_array($op, $ops)) { // did we end with an operator? bad.
-                    return $this->trigger("operator '$op' lacks operand");
+                    return $this->trigger(get_string('operatorlacksoperand', 'mathslib', $op));
                 } else {
                     break;
                 }
@@ -313,7 +353,7 @@ class EvalMath {
 
         }
         while (!is_null($op = $stack->pop())) { // pop everything off the stack and push onto output
-            if ($op == '(') return $this->trigger("expecting ')'"); // if there are (s on the stack, ()s were unbalanced
+            if ($op == '(') return $this->trigger(get_string('expectingaclosingbracket', 'mathslib')); // if there are (s on the stack, ()s were unbalanced
             $output[] = $op;
         }
         return $output;
@@ -333,7 +373,7 @@ class EvalMath {
                 $fnn = $token['fnn'];
                 $count = $token['argcount'];
                 if (in_array($fnn, $this->fb)) { // built-in function:
-                    if (is_null($op1 = $stack->pop())) return $this->trigger("internal error");
+                    if (is_null($op1 = $stack->pop())) return $this->trigger(get_string('internalerror', 'mathslib'));
                     $fnn = preg_replace("/^arc/", "a", $fnn); // for the 'arc' trig synonyms
                     if ($fnn == 'ln') $fnn = 'log';
                     eval('$stack->push(' . $fnn . '($op1));'); // perfectly safe eval()
@@ -341,25 +381,26 @@ class EvalMath {
                     // get args
                     $args = array();
                     for ($i = $count-1; $i >= 0; $i--) {
-                        if (is_null($args[] = $stack->pop())) return $this->trigger("internal error");
+                        if (is_null($args[] = $stack->pop())) return $this->trigger(get_string('internalerror', 'mathslib'));
                     }
-                    $res = call_user_func(array('EvalMathCalcEmul', $fnn), $args);
+                    $classname = 'EvalMathCalcEmul_'.$fnn;
+                    $res = call_user_func(array($classname, 'calculate'), $args);
                     if ($res === FALSE) {
-                        return $this->trigger("internal error");
+                        return $this->trigger(get_string('internalerror', 'mathslib'));
                     }
                     $stack->push($res);
                 } elseif (array_key_exists($fnn, $this->f)) { // user function
                     // get args
                     $args = array();
                     for ($i = count($this->f[$fnn]['args'])-1; $i >= 0; $i--) {
-                        if (is_null($args[$this->f[$fnn]['args'][$i]] = $stack->pop())) return $this->trigger("internal error");
+                        if (is_null($args[$this->f[$fnn]['args'][$i]] = $stack->pop())) return $this->trigger(get_string('internalerror', 'mathslib'));
                     }
                     $stack->push($this->pfx($this->f[$fnn]['func'], $args)); // yay... recursion!!!!
                 }
             // if the token is a binary operator, pop two values off the stack, do the operation, and push the result back on
             } elseif (in_array($token, array('+', '-', '*', '/', '^'), true)) {
-                if (is_null($op2 = $stack->pop())) return $this->trigger("internal error");
-                if (is_null($op1 = $stack->pop())) return $this->trigger("internal error");
+                if (is_null($op2 = $stack->pop())) return $this->trigger(get_string('internalerror', 'mathslib'));
+                if (is_null($op1 = $stack->pop())) return $this->trigger(get_string('internalerror', 'mathslib'));
                 switch ($token) {
                     case '+':
                         $stack->push($op1+$op2); break;
@@ -368,7 +409,7 @@ class EvalMath {
                     case '*':
                         $stack->push($op1*$op2); break;
                     case '/':
-                        if ($op2 == 0) return $this->trigger("division by zero");
+                        if ($op2 == 0) return $this->trigger(get_string('divisionbyzero', 'mathslib'));
                         $stack->push($op1/$op2); break;
                     case '^':
                         $stack->push(pow($op1, $op2)); break;
@@ -385,12 +426,12 @@ class EvalMath {
                 } elseif (array_key_exists($token, $vars)) {
                     $stack->push($vars[$token]);
                 } else {
-                    return $this->trigger("undefined variable '$token'");
+                    return $this->trigger(get_string('undefinedvariable', 'mathslib', $token));
                 }
             }
         }
         // when we're out of tokens, the stack should have a single element, the final result
-        if ($stack->count != 1) return $this->trigger("internal error");
+        if ($stack->count != 1) return $this->trigger(get_string('internalerror', 'mathslib'));
         return $stack->pop();
     }
 
@@ -400,6 +441,7 @@ class EvalMath {
         if (!$this->suppress_errors) trigger_error($msg, E_USER_WARNING);
         return false;
     }
+
 }
 
 // for internal use
@@ -429,15 +471,18 @@ class EvalMathStack {
     }
 }
 
+
 // spreadsheet functions emulation
 // watch out for reversed args!!
-class EvalMathCalcEmul {
+class EvalMathCalcEmul_average {
 
-    function average($args) {
-        return (EvalMathCalcEmul::sum($args)/count($args));
+    static function calculate($args) {
+        return (EvalMathCalcEmul_sum::calculate($args)/count($args));
     }
+}
 
-    function max($args) {
+class EvalMathCalcEmul_max  {
+    static function calculate($args) {
         $res = array_pop($args);
         foreach($args as $a) {
             if ($res < $a) {
@@ -446,8 +491,10 @@ class EvalMathCalcEmul {
         }
         return $res;
     }
+}
 
-    function min($args) {
+class EvalMathCalcEmul_min  {
+    static function calculate($args) {
         $res = array_pop($args);
         foreach($args as $a) {
             if ($res > $a) {
@@ -456,28 +503,34 @@ class EvalMathCalcEmul {
         }
         return $res;
     }
-
-    function mod($args) {
+}
+class EvalMathCalcEmul_mod {
+    static function calculate($args) {
         return $args[1] % $args[0];
     }
-
-    function pi($args) {
+}
+class EvalMathCalcEmul_pi {
+    static function calculate($args) {
         return pi();
     }
-
-    function power($args) {
+}
+class EvalMathCalcEmul_power {
+    static function calculate($args) {
         return $args[1]^$args[0];
     }
+}
 
-    function round($args) {
+class EvalMathCalcEmul_round {
+    static function calculate($args) {
         if (count($args)==1) {
             return round($args[0]);
         } else {
             return round($args[1], $args[0]);
         }
     }
-
-    function sum($args) {
+}
+class EvalMathCalcEmul_sum {
+    static function calculate($args) {
         $res = 0;
         foreach($args as $a) {
            $res += $a;
@@ -485,3 +538,47 @@ class EvalMathCalcEmul {
         return $res;
     }
 }
+class EvalMathCalcEmul_randomised {
+    protected static $randomseed = null;
+
+    static function set_random_seed($randomseed) {
+        self::$randomseed = $randomseed;
+    }
+
+    static function get_random_seed() {
+        if (is_null(self::$randomseed)){
+            return microtime();
+        } else {
+            return self::$randomseed;
+        }
+    }
+
+}
+
+class EvalMathCalcEmul_rand_int extends EvalMathCalcEmul_randomised {
+    static function calculate($args){
+        $min = $args[1];
+        $max = $args[0];
+        if ($min >= $max) {
+            return false; //error
+        }
+        $noofchars = ceil(log($max + 1 - $min, '16'));
+        $md5string = md5(self::get_random_seed());
+        $stringoffset = 0;
+        do {
+            while (($stringoffset + $noofchars) > strlen($md5string)){
+                $md5string .= md5($md5string);
+            }
+            $randomno = hexdec(substr($md5string, $stringoffset, $noofchars));
+            $stringoffset += $noofchars;
+        } while (($min + $randomno) > $max);
+        return $min + $randomno;
+    }
+}
+class EvalMathCalcEmul_rand_float extends EvalMathCalcEmul_randomised {
+    static function calculate(){
+        $randomvalue = array_shift(unpack('v', md5(self::get_random_seed(), true)));
+        return $randomvalue / 65536;
+    }
+
+}
index acfbeee..0105d56 100644 (file)
@@ -1,11 +1,16 @@
 Description of EvalMath library import into Moodle
 
 Our changes:
-* implicit multiplication not allowed
+* implicit multiplication (optionally) not allowed
 * new custom calc emulation functions
-* removed e and pi constants - not used in calc
+* removed (optionally) e and pi constants - not used in calc
 * removed sample files
 * Fix a == FALSE that should have been === FALSE.
+* added $expecting_op = true; for branch where a function with no operands is found to fix bug.
+* moved pattern for func and var names into a static var
+* made a function to test a string to see if it is a valid func or var name.
+* localized strings
+* added round, ceil and floor functions.
 
 To see all changes diff against version 1.1, available from:
 http://www.phpclasses.org/browse/package/2695.html
index a45afa2..5fbc20b 100644 (file)
@@ -133,7 +133,7 @@ function message_send($eventdata) {
         // Find out if user has configured this output
         $userisconfigured = $processor->object->is_user_configured($eventdata->userto);
 
-        // DEBUG: noify if we are forcing unconfigured output
+        // DEBUG: notify if we are forcing unconfigured output
         if ($permitted == 'forced' && !$userisconfigured) {
             debugging('Attempt to force message delivery to user who has "'.$processor->name.'" output unconfigured', DEBUG_NORMAL);
         }
index 997d68d..223dcde 100644 (file)
@@ -3920,12 +3920,6 @@ function set_login_session_preferences() {
     $SESSION->justloggedin = true;
 
     unset($SESSION->lang);
-
-    // Restore the calendar filters, if saved
-    if (intval(get_user_preferences('calendar_persistflt', 0))) {
-        include_once($CFG->dirroot.'/calendar/lib.php');
-        calendar_set_filters_status(get_user_preferences('calendar_savedflt', 0xff));
-    }
 }
 
 
@@ -7049,6 +7043,8 @@ function get_core_subsystems() {
             'iso6392'     => NULL,
             'langconfig'  => NULL,
             'license'     => NULL,
+            'mathslib'    => NULL,
+            'message'     => 'message',
             'message'     => 'message',
             'mimetypes'   => NULL,
             'mnet'        => 'mnet',
index 3efae16..9691409 100644 (file)
@@ -2267,6 +2267,9 @@ class global_navigation extends navigation_node {
             $coursenode->add(get_string('tags', 'tag'), new moodle_url('/tag/search.php'));
         }
 
+        // Calendar
+        $calendarurl = new moodle_url('/calendar/view.php', array('view' => 'month'));
+        $coursenode->add(get_string('calendar', 'calendar'), $calendarurl, self::TYPE_CUSTOM, null, 'calendar');
 
         // View course reports
         if (has_capability('moodle/site:viewreports', $this->page->context)) { // basic capability for listing of reports
index 7f63cf3..9f2bb83 100644 (file)
@@ -1625,7 +1625,7 @@ class core_renderer extends renderer_base {
         $title = get_string($helpicon->identifier, $helpicon->component);
 
         if (empty($helpicon->linktext)) {
-            $alt = $title;
+            $alt = get_string('helpprefix2', '', trim($title, ". \t"));
         } else {
             $alt = get_string('helpwiththis');
         }
index b6c9cf0..34c1c91 100644 (file)
@@ -340,7 +340,9 @@ class moodle_page {
                 // cli scripts work in system context, do not annoy devs with debug info
                 // very few scripts do not use cookies, we can safely use system as default context there
             } else {
-                debugging('Coding problem: this page does not set $PAGE->context properly.');
+                debugging('Coding problem: $PAGE->context was not set. You may have forgotten '
+                    .'to call require_login() or $PAGE->set_context(). The page may not display '
+                    .'correctly as a result');
             }
             $this->_context = get_context_instance(CONTEXT_SYSTEM);
         }
index 5c7d89f..fe52dfe 100644 (file)
@@ -640,13 +640,25 @@ function question_move_category_to_context($categoryid, $oldcontextid, $newconte
  * @param question_display_options $displayoptions the display options to use.
  * @param int $variant the variant of the question to preview. If null, one will
  *      be picked randomly.
+ * @param object $context context to run the preview in (affects things like
+ *      filter settings, theme, lang, etc.) Defaults to $PAGE->context.
  * @return string the URL.
  */
 function question_preview_url($questionid, $preferredbehaviour = null,
-        $maxmark = null, $displayoptions = null, $variant = null) {
+        $maxmark = null, $displayoptions = null, $variant = null, $context = null) {
 
     $params = array('id' => $questionid);
 
+    if (is_null($context)) {
+        global $PAGE;
+        $context = $PAGE->context;
+    }
+    if ($context->contextlevel == CONTEXT_MODULE) {
+        $params['cmid'] = $context->instanceid;
+    } else if ($context->contextlevel == CONTEXT_COURSE) {
+        $params['courseid'] = $context->instanceid;
+    }
+
     if (!is_null($preferredbehaviour)) {
         $params['behaviour'] = $preferredbehaviour;
     }
@@ -1826,7 +1838,7 @@ function question_make_export_url($contextid, $categoryid, $format, $withcategor
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function question_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function question_page_type_list($pagetype, $parentcontext, $currentcontext) {
     global $CFG;
     $types = array(
         'question-*'=>get_string('page-question-x', 'question'),
@@ -1837,7 +1849,7 @@ function question_pagetypelist($pagetype, $parentcontext, $currentcontext) {
     );
     if ($currentcontext->contextlevel == CONTEXT_COURSE) {
         require_once($CFG->dirroot . '/course/lib.php');
-        return array_merge(course_pagetypelist($pagetype, $parentcontext, $currentcontext), $types);
+        return array_merge(course_page_type_list($pagetype, $parentcontext, $currentcontext), $types);
     } else {
         return $types;
     }
index ead572f..a17bd0a 100644 (file)
@@ -76,6 +76,110 @@ class mathsslib_test extends UnitTestCase {
         $this->assertEqual($res, 60, 'sum is: %s');
     }
 
+    /**
+     * Tests some slightly more complex expressions
+     */
+    function test__more_complex_expressions() {
+        $formula = new calc_formula('=pi() + a', array('a'=>10));
+        $res = $formula->evaluate();
+        $this->assertEqual($res, pi()+10);
+        $formula = new calc_formula('=pi()^a', array('a'=>10));
+        $res = $formula->evaluate();
+        $this->assertEqual($res, pow(pi(),10));
+        $formula = new calc_formula('=-8*(5/2)^2*(1-sqrt(4))-8');
+        $res = $formula->evaluate();
+        $this->assertEqual($res, -8*pow((5/2),2)*(1-sqrt(4))-8);
+    }
+
+    /**
+     * Tests some slightly more complex expressions
+     */
+    function test__error_handling() {
+        if (debugging('', DEBUG_DEVELOPER)){
+            $this->expectError();
+        }
+        $formula = new calc_formula('=pi( + a', array('a'=>10));
+        $res = $formula->evaluate();
+        $this->assertEqual($res, false);
+        $this->assertEqual($formula->get_error(), get_string('unexpectedoperator', 'mathslib', '+'));
+
+        if (debugging('', DEBUG_DEVELOPER)){
+            $this->expectError();
+        }
+        $formula = new calc_formula('=pi(');
+        $res = $formula->evaluate();
+        $this->assertEqual($res, false);
+        $this->assertEqual($formula->get_error(), get_string('expectingaclosingbracket', 'mathslib'));
+
+        if (debugging('', DEBUG_DEVELOPER)){
+            $this->expectError();
+        }
+        $formula = new calc_formula('=pi()^');
+        $res = $formula->evaluate();
+        $this->assertEqual($res, false);
+        $this->assertEqual($formula->get_error(), get_string('operatorlacksoperand', 'mathslib', '^'));
+
+    }
+
+    function test_rounding_function() {
+        $formula = new calc_formula('=round(2.5)');
+        $this->assertEqual($formula->evaluate(), 3);
+
+        $formula = new calc_formula('=round(1.5)');
+        $this->assertEqual($formula->evaluate(), 2);
+
+        $formula = new calc_formula('=round(-1.49)');
+        $this->assertEqual($formula->evaluate(), -1);
+
+        $formula = new calc_formula('=round(-2.49)');
+        $this->assertEqual($formula->evaluate(), -2);
+
+        $formula = new calc_formula('=round(-1.5)');
+        $this->assertEqual($formula->evaluate(), -2);
+
+        $formula = new calc_formula('=round(-2.5)');
+        $this->assertEqual($formula->evaluate(), -3);
+
+
+        $formula = new calc_formula('=ceil(2.5)');
+        $this->assertEqual($formula->evaluate(), 3);
+
+        $formula = new calc_formula('=ceil(1.5)');
+        $this->assertEqual($formula->evaluate(), 2);
+
+        $formula = new calc_formula('=ceil(-1.49)');
+        $this->assertEqual($formula->evaluate(), -1);
+
+        $formula = new calc_formula('=ceil(-2.49)');
+        $this->assertEqual($formula->evaluate(), -2);
+
+        $formula = new calc_formula('=ceil(-1.5)');
+        $this->assertEqual($formula->evaluate(), -1);
+
+        $formula = new calc_formula('=ceil(-2.5)');
+        $this->assertEqual($formula->evaluate(), -2);
+
+
+        $formula = new calc_formula('=floor(2.5)');
+        $this->assertEqual($formula->evaluate(), 2);
+
+        $formula = new calc_formula('=floor(1.5)');
+        $this->assertEqual($formula->evaluate(), 1);
+
+        $formula = new calc_formula('=floor(-1.49)');
+        $this->assertEqual($formula->evaluate(), -2);
+
+        $formula = new calc_formula('=floor(-2.49)');
+        $this->assertEqual($formula->evaluate(), -3);
+
+        $formula = new calc_formula('=floor(-1.5)');
+        $this->assertEqual($formula->evaluate(), -2);
+
+        $formula = new calc_formula('=floor(-2.5)');
+        $this->assertEqual($formula->evaluate(), -3);
+
+    }
+
 }
 
 
index dfb7d1a..e27388d 100644 (file)
@@ -531,7 +531,7 @@ function local_qeupgradehelper_generate_unit_test($questionsessionid, $namesuffi
     if (!local_qeupgradehelper_is_upgraded()) {
         if (!$quiz->optionflags) {
             $quiz->preferredbehaviour = 'deferredfeedback';
-        } else if (!$quiz->penaltyscheme) {
+        } else if ($quiz->penaltyscheme) {
             $quiz->preferredbehaviour = 'adaptive';
         } else {
             $quiz->preferredbehaviour = 'adaptivenopenalty';
index 00f24a8..1a7a160 100644 (file)
@@ -31,7 +31,7 @@ class moodle_message_external extends external_api {
      * Returns description of method parameters
      * @return external_function_parameters
      */
-    public static function send_messages_parameters() {
+    public static function send_instantmessages_parameters() {
         return new external_function_parameters(
             array(
                 'messages' => new external_multiple_structure(
@@ -53,7 +53,7 @@ class moodle_message_external extends external_api {
      * @param $messages  An array of message to send.
      * @return boolean
      */
-    public static function send_messages($messages = array()) {
+    public static function send_instantmessages($messages = array()) {
         global $CFG, $USER, $DB;
         require_once($CFG->dirroot . "/message/lib.php");
 
@@ -67,24 +67,32 @@ class moodle_message_external extends external_api {
         self::validate_context($context);
         require_capability('moodle/site:sendmessage', $context);
 
-        $params = self::validate_parameters(self::send_messages_parameters(), array('messages' => $messages));
+        $params = self::validate_parameters(self::send_instantmessages_parameters(), array('messages' => $messages));
 
         //retrieve all tousers of the messages
-        $touserids = array();
+        $receivers = array();
         foreach($params['messages'] as $message) {
-            $touserids[] = $message['touserid'];
+            $receivers[] = $message['touserid'];
         }
-        list($sqluserids, $sqlparams) = $DB->get_in_or_equal($touserids, SQL_PARAMS_NAMED, 'userid_');
+        list($sqluserids, $sqlparams) = $DB->get_in_or_equal($receivers, SQL_PARAMS_NAMED, 'userid_');
         $tousers = $DB->get_records_select("user", "id " . $sqluserids . " AND deleted = 0", $sqlparams);
-
-        //retrieve the tousers who are blocking the $USER
+        $blocklist   = array();
+        $contactlist = array();
         $sqlparams['contactid'] = $USER->id;
-        $sqlparams['blocked'] = 1;
-        //Note: return userid field should be unique for the below request,
-        //so we'll use this field as key of $blockingcontacts
-        $blockingcontacts = $DB->get_records_select("message_contacts",
-                "userid " . $sqluserids . " AND contactid = :contactid AND blocked = :blocked",
-                $sqlparams, '', "userid");
+        $rs = $DB->get_recordset_sql("SELECT *
+                                        FROM {message_contacts}
+                                       WHERE userid $sqluserids
+                                             AND contactid = :contactid", $sqlparams);
+        foreach ($rs as $record) {
+            if ($record->blocked) {
+                // $record->userid is blocking current user
+                $blocklist[$record->userid] = true;
+            } else {
+                // $record->userid have current user as contact
+                $contactlist[$record->userid] = true;
+            }
+        }
+        $rs->close();
 
         $canreadallmessages = has_capability('moodle/site:readallmessages', $context);
 
@@ -104,14 +112,16 @@ class moodle_message_external extends external_api {
             }
 
             //check that the touser is not blocking the current user
-            if ($success and isset($blockingcontacts[$message['touserid']]) and !$canreadallmessages) {
+            if ($success and !empty($blocklist[$message['touserid']]) and !$canreadallmessages) {
                 $success = false;
                 $errormessage = get_string('userisblockingyou', 'message');
             }
 
             // Check if the user is a contact
             //TODO: performance improvement - edit the function so we can pass an array instead userid
-            if ($success && empty($contact) && get_user_preferences('message_blocknoncontacts', NULL, $message['touserid']) == null) {
+            $blocknoncontacts = get_user_preferences('message_blocknoncontacts', NULL, $message['touserid']);
+            // message_blocknoncontacts option is on and current user is not in contact list
+            if ($success && empty($contactlist[$message['touserid']]) && !empty($blocknoncontacts)) {
                 // The user isn't a contact and they have selected to block non contacts so this message won't be sent.
                 $success = false;
                 $errormessage = get_string('userisblockingyounoncontact', 'message');
@@ -144,12 +154,12 @@ class moodle_message_external extends external_api {
      * Returns description of method result value
      * @return external_description
      */
-    public static function send_messages_returns() {
+    public static function send_instantmessages_returns() {
         return new external_multiple_structure(
             new external_single_structure(
                 array(
-                    'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
                     'msgid' => new external_value(PARAM_INT, 'test this to know if it succeeds:  id of the created message if it succeeded, -1 when failed'),
+                    'clientmsgid' => new external_value(PARAM_ALPHANUMEXT, 'your own id for the message', VALUE_OPTIONAL),
                     'errormessage' => new external_value(PARAM_TEXT, 'error message - if it failed', VALUE_OPTIONAL)
                 )
             )
index 8020453..9de50e0 100644 (file)
@@ -2369,6 +2369,6 @@ function translate_message_default_setting($plugindefault, $processorname) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function message_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function message_page_type_list($pagetype, $parentcontext, $currentcontext) {
     return array('messages-*'=>get_string('page-message-x', 'message'));
 }
index aec18b6..b7f559e 100644 (file)
@@ -45,6 +45,8 @@ You can see it appended to your assignment submission:
 $string['assignmentmailhtml'] = '{$a->teacher} has posted some feedback on your
 assignment submission for \'<i>{$a->assignment}</i>\'<br /><br />
 You can see it appended to your <a href="{$a->url}">assignment submission</a>.';
+$string['assignmentmailsmall'] = '{$a->teacher} has posted some feedback on your
+assignment submission for \'{$a->assignment}\' You can see it appended to your submission';
 $string['assignmentname'] = 'Assignment name';
 $string['assignment:submit'] = 'Submit assignment';
 $string['assignmentsubmission'] = 'Assignment submissions';
@@ -90,8 +92,8 @@ $string['emailteachers_help'] = 'If enabled, teachers receive email notification
 
 Only teachers who are able to grade the particular assignment are notified. So, for example, if the course uses separate groups, teachers restricted to particular groups won\'t receive notification about students in other groups.';
 $string['emptysubmission'] = 'You have not submitted anything yet';
-$string['enableemailnotification'] = 'Send notification emails';
-$string['enableemailnotification_help'] = 'If enabled, students will receive email notification when their assignment submissions are graded.';
+$string['enablenotification'] = 'Send notifications';
+$string['enablenotification_help'] = 'If enabled, students will be notified when their assignment submissions are graded.';
 $string['errornosubmissions'] = 'There are no submissions to download';
 $string['existingfiledeleted'] = 'Existing file has been deleted: {$a}';
 $string['failedupdatefeedback'] = 'Failed to update submission feedback for user {$a}';
index 13cb271..84665f8 100644 (file)
@@ -1021,6 +1021,7 @@ class assignment_base {
         $mformdata->submissioncommentformat= FORMAT_HTML;
         $mformdata->submission_content= $this->print_user_files($user->id,true);
         $mformdata->filter = $filter;
+        $mformdata->mailinfo = get_user_preferences('assignment_mailinfo', 0);
          if ($assignment->assignmenttype == 'upload') {
             $mformdata->fileui_options = array('subdirs'=>1, 'maxbytes'=>$assignment->maxbytes, 'maxfiles'=>$assignment->var1, 'accepted_types'=>'*', 'return_types'=>FILE_INTERNAL);
         } elseif ($assignment->assignmenttype == 'uploadsingle') {
@@ -1470,9 +1471,9 @@ class assignment_base {
             if (get_user_preferences('assignment_mailinfo', 1)) {
                 $mailinfopref = true;
             }
-            $emailnotification =  html_writer::checkbox('mailinfo', 1, $mailinfopref, get_string('enableemailnotification','assignment'));
+            $emailnotification =  html_writer::checkbox('mailinfo', 1, $mailinfopref, get_string('enablenotification','assignment'));
 
-            $emailnotification .= $OUTPUT->help_icon('enableemailnotification', 'assignment');
+            $emailnotification .= $OUTPUT->help_icon('enablenotification', 'assignment');
             echo html_writer::tag('div', $emailnotification, array('class'=>'emailnotification'));
 
             $savefeedback = html_writer::empty_tag('input', array('type'=>'submit', 'name'=>'fastg', 'value'=>get_string('saveallfeedback', 'assignment')));
@@ -1746,7 +1747,7 @@ class assignment_base {
                 $eventdata->fullmessage      = $posttext;
                 $eventdata->fullmessageformat = FORMAT_PLAIN;
                 $eventdata->fullmessagehtml  = $posthtml;
-                $eventdata->smallmessage     = '';
+                $eventdata->smallmessage     = $postsubject;
 
                 $eventdata->name            = 'assignment_updates';
                 $eventdata->component       = 'mod_assignment';
@@ -2303,12 +2304,10 @@ class mod_assignment_grading_form extends moodleform {
                 default :
                     break;
             }
-            $lastmailinfo = get_user_preferences('assignment_mailinfo', 1) ? array('checked'=>'checked') : array();
             $mform->addElement('hidden', 'mailinfo_h', "0");
             $mform->setType('mailinfo_h', PARAM_INT);
-            $mform->addElement('checkbox', 'mailinfo',get_string('enableemailnotification','assignment').
-            $OUTPUT->help_icon('enableemailnotification', 'assignment') .':' );
-            $mform->updateElementAttr('mailinfo', $lastmailinfo);
+            $mform->addElement('checkbox', 'mailinfo',get_string('enablenotification','assignment').
+            $OUTPUT->help_icon('enablenotification', 'assignment') .':' );
             $mform->setType('mailinfo', PARAM_INT);
         }
     }
@@ -2616,11 +2615,13 @@ function assignment_cron () {
             $eventdata->fullmessage      = $posttext;
             $eventdata->fullmessageformat = FORMAT_PLAIN;
             $eventdata->fullmessagehtml  = $posthtml;
-            $eventdata->smallmessage     = '';
+            $eventdata->smallmessage     = get_string('assignmentmailsmall', 'assignment', $assignmentinfo);
 
             $eventdata->name            = 'assignment_updates';
             $eventdata->component       = 'mod_assignment';
             $eventdata->notification    = 1;
+            $eventdata->contexturl      = $assignmentinfo->url;
+            $eventdata->contexturlname  = $assignmentinfo->assignment;
 
             message_send($eventdata);
         }
@@ -3722,7 +3723,7 @@ function assignment_get_file_areas($course, $cm, $context) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function assignment_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function assignment_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array(
         'mod-assignment-*'=>get_string('page-mod-assignment-x', 'assignment'),
         'mod-assignment-view'=>get_string('page-mod-assignment-view', 'assignment'),
index c40b833..a59a5e2 100644 (file)
@@ -1312,7 +1312,7 @@ function chat_user_logout($user) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function chat_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function chat_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-chat-*'=>get_string('page-mod-chat-x', 'chat'));
     return $module_pagetype;
 }
index b9b1fa0..a03db26 100644 (file)
@@ -863,7 +863,7 @@ function choice_get_completion_state($course, $cm, $userid, $type) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function choice_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function choice_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-choice-*'=>get_string('page-mod-choice-x', 'choice'));
     return $module_pagetype;
 }
index 3bd234e..7b045da 100644 (file)
@@ -31,7 +31,8 @@ class mod_data_export_form extends moodleform {
         $typesarray = array();
         $typesarray[] = &MoodleQuickForm::createElement('radio', 'exporttype', null, get_string('csvwithselecteddelimiter', 'data') . '&nbsp;', 'csv');
         $typesarray[] = &MoodleQuickForm::createElement('select', 'delimiter_name', null, $choices);
-        $typesarray[] = &MoodleQuickForm::createElement('radio', 'exporttype', null, get_string('excel', 'data'), 'xls');
+        //temporarily commenting out Excel export option. See MDL-19864
+        //$typesarray[] = &MoodleQuickForm::createElement('radio', 'exporttype', null, get_string('excel', 'data'), 'xls');
         $typesarray[] = &MoodleQuickForm::createElement('radio', 'exporttype', null, get_string('ods', 'data'), 'ods');
         $mform->addGroup($typesarray, 'exportar', '', array(''), false);
         $mform->addRule('exportar', null, 'required');
index ff954dd..8758bfc 100644 (file)
@@ -3344,7 +3344,7 @@ function data_comment_validate($comment_param) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function data_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function data_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-data-*'=>get_string('page-mod-data-x', 'data'));
     return $module_pagetype;
 }
index af2dfcb..30402b2 100644 (file)
@@ -213,11 +213,7 @@ class feedback_item_multichoice extends feedback_item_base {
             $analysedVals = $analysedItem[2];
             $pixnr = 0;
             foreach($analysedVals as $val) {
-                if( function_exists("bcmod")) {
-                    $intvalue = bcmod($pixnr, 10);
-                }else {
-                    $intvalue = 0;
-                }
+                $intvalue = $pixnr % 10;
                 $pix = "pics/$intvalue.gif";
                 $pixnr++;
                 $pixwidth = intval($val->quotient * FEEDBACK_MAX_PIX_LENGTH);
index 77a2b04..41764e9 100644 (file)
@@ -184,11 +184,7 @@ class feedback_item_multichoicerated extends feedback_item_base {
             $pixnr = 0;
             $avg = 0.0;
             foreach($analysedVals as $val) {
-                if( function_exists("bcmod")) {
-                    $intvalue = bcmod($pixnr, 10);
-                }else {
-                    $intvalue = 0;
-                }
+                $intvalue = $pixnr % 10;
                 $pix = "pics/$intvalue.gif";
                 $pixnr++;
                 $pixwidth = intval($val->quotient * FEEDBACK_MAX_PIX_LENGTH);
index b777e7e..bf046a3 100644 (file)
@@ -493,6 +493,20 @@ function feedback_scale_used_anywhere($scaleid) {
     return false;
 }
 
+/**
+ * @return array
+ */
+function feedback_get_view_actions() {
+    return array('view','view all');
+}
+
+/**
+ * @return array
+ */
+function feedback_get_post_actions() {
+    return array('submit');
+}
+
 /**
  * This function is used by the reset_course_userdata function in moodlelib.
  * This function will remove all responses from the specified feedback
@@ -2788,7 +2802,7 @@ function feedback_init_feedback_session() {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function feedback_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function feedback_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-feedback-*'=>get_string('page-mod-feedback-x', 'feedback'));
     return $module_pagetype;
 }
index 20775d5..491e5ed 100644 (file)
@@ -343,7 +343,7 @@ function folder_extend_navigation($navigation, $course, $module, $cm) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function folder_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function folder_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-folder-*'=>get_string('page-mod-folder-x', 'folder'));
     return $module_pagetype;
 }
index 03ad341..208e008 100644 (file)
@@ -7964,7 +7964,7 @@ function forum_cm_info_view(cm_info $cm) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function forum_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function forum_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $forum_pagetype = array(
         'mod-forum-*'=>get_string('page-mod-forum-x', 'forum'),
         'mod-forum-view'=>get_string('page-mod-forum-view', 'forum'),
index d488752..8df1014 100644 (file)
@@ -2861,7 +2861,7 @@ function glossary_comment_validate($comment_param) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function glossary_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function glossary_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-glossary-*'=>get_string('page-mod-glossary-x', 'glossary'));
     return $module_pagetype;
 }
index 697c293..af804cf 100644 (file)
@@ -407,7 +407,7 @@ function imscp_extend_navigation($navigation, $course, $module, $cm) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function imscp_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function imscp_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-imscp-*'=>get_string('page-mod-imscp-x', 'imscp'));
     return $module_pagetype;
 }
index d207aae..384cb47 100644 (file)
@@ -67,6 +67,13 @@ if (!$canmanage) {
 
 // record answer (if necessary) and show response (if none say if answer is correct or not)
 $page = $lesson->load_page(required_param('pageid', PARAM_INT));
+
+$userhasgrade = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$USER->id));
+$reviewmode = false;
+if ($userhasgrade && !$lesson->retake) {
+    $reviewmode = true;
+}
+
 // Check the page has answers [MDL-25632]
 if (count($page->answers) > 0) {
     $result = $page->record_attempt($context);
@@ -80,7 +87,7 @@ if (count($page->answers) > 0) {
 
 if (isset($USER->modattempts[$lesson->id])) {
     // make sure if the student is reviewing, that he/she sees the same pages/page path that he/she saw the first time
-    if ($USER->modattempts[$lesson->id] == $page->id && $page->nextpageid == 0) {  // remember, this session variable holds the pageid of the last page that the user saw
+    if ($USER->modattempts[$lesson->id]->pageid == $page->id && $page->nextpageid == 0) {  // remember, this session variable holds the pageid of the last page that the user saw
         $result->newpageid = LESSON_EOL;
     } else {
         $nretakes = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$USER->id));
@@ -153,11 +160,11 @@ if ($canmanage) {
     }
 }
 // Report attempts remaining
-if ($result->attemptsremaining != 0 && !$lesson->review) {
+if ($result->attemptsremaining != 0 && !$lesson->review && !$reviewmode) {
     $lesson->add_message(get_string('attemptsremaining', 'lesson', $result->attemptsremaining));
 }
 // Report if max attempts reached
-if ($result->maxattemptsreached != 0 && !$lesson->review) {
+if ($result->maxattemptsreached != 0 && !$lesson->review && !$reviewmode) {
     $lesson->add_message('('.get_string("maximumnumberofattemptsreached", "lesson").')');
 }
 
@@ -172,7 +179,7 @@ if ($lesson->displayleft) {
     echo '<a name="maincontent" id="maincontent" title="'.get_string('anchortitle', 'lesson').'"></a>';
 }
 // This calculates and prints the ongoing score message
-if ($lesson->ongoing) {
+if ($lesson->ongoing && !$reviewmode) {
     echo $lessonoutput->ongoing_score($lesson);
 }
 echo $result->feedback;
@@ -180,17 +187,17 @@ echo $result->feedback;
 // User is modifying attempts - save button and some instructions
 if (isset($USER->modattempts[$lesson->id])) {
     $url = $CFG->wwwroot.'/mod/lesson/view.php';
-    $content = $OUTPUT->box(get_string("savechangesandeol", "lesson"), 'center');
+    $content = $OUTPUT->box(get_string("gotoendoflesson", "lesson"), 'center');
     $content .= $OUTPUT->box(get_string("or", "lesson"), 'center');
-    $content .= $OUTPUT->box(get_string("continuetoanswer", "lesson"), 'center');
+    $content .= $OUTPUT->box(get_string("continuetonextpage", "lesson"), 'center');
     $content .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'id', 'value'=>$cm->id));
     $content .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'pageid', 'value'=>LESSON_EOL));
-    $content .= html_writer::empty_tag('input', array('type'=>'submit', 'name'=>'submit', 'value'=>get_string('savechanges', 'lesson')));
+    $content .= html_writer::empty_tag('input', array('type'=>'submit', 'name'=>'submit', 'value'=>get_string('finish', 'lesson')));
     echo html_writer::tag('form', "<div>$content</div>", array('method'=>'post', 'action'=>$url));
 }
 
 // Review button back
-if ($lesson->review && !$result->correctanswer && !$result->noanswer && !$result->isessayquestion) {
+if (!$result->correctanswer && !$result->noanswer && !$result->isessayquestion && !$reviewmode) {
     $url = $CFG->wwwroot.'/mod/lesson/view.php';
     $content = html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'id', 'value'=>$cm->id));
     $content .= html_writer::empty_tag('input', array('type'=>'hidden', 'name'=>'pageid', 'value'=>$page->id));
index 6f131ad..11fbd4a 100644 (file)
@@ -97,7 +97,8 @@ function lesson_save_question_options($question, $lesson) {
                     $answer->timecreated   = $timenow;
                     $answer->grade = $question->fraction[$key] * 100;
                     $answer->answer   = $dataanswer;
-                    $answer->response = $question->feedback[$key];
+                    $answer->response = $question->feedback[$key]['text'];
+                    $answer->responseformat = $question->feedback[$key]['format'];
                     $answer->id = $DB->insert_record("lesson_answers", $answer);
                     $answers[] = $answer->id;
                     if ($question->fraction[$key] > $maxfraction) {
@@ -134,7 +135,8 @@ function lesson_save_question_options($question, $lesson) {
                     $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];
+                    $answer->response = $question->feedback[$key]['text'];
+                    $answer->responseformat = $question->feedback[$key]['format'];
                     $answer->id = $DB->insert_record("lesson_answers", $answer);
 
                     $answers[] = $answer->id;
@@ -160,12 +162,13 @@ function lesson_save_question_options($question, $lesson) {
             $answer->pageid = $question->id;
             $answer->timecreated   = $timenow;
             $answer->answer = get_string("true", "quiz");
-            $answer->grade = $question->answer * 100;
+            $answer->grade = $question->correctanswer * 100;
             if ($answer->grade > 50 ) {
                 $answer->jumpto = LESSON_NEXTPAGE;
             }
             if (isset($question->feedbacktrue)) {
-                $answer->response = $question->feedbacktrue;
+                $answer->response = $question->feedbacktrue['text'];
+                $answer->responseformat = $question->feedbacktrue['format'];
             }
             $DB->insert_record("lesson_answers", $answer);
 
@@ -175,12 +178,13 @@ function lesson_save_question_options($question, $lesson) {
             $answer->pageid = $question->id;
             $answer->timecreated   = $timenow;
             $answer->answer = get_string("false", "quiz");
-            $answer->grade = (1 - (int)$question->answer) * 100;
+            $answer->grade = (1 - (int)$question->correctanswer) * 100;
             if ($answer->grade > 50 ) {
                 $answer->jumpto = LESSON_NEXTPAGE;
             }
             if (isset($question->feedbackfalse)) {
-                $answer->response = $question->feedbackfalse;
+                $answer->response = $question->feedbackfalse['text'];
+                $answer->responseformat = $question->feedbackfalse['format'];
             }
             $DB->insert_record("lesson_answers", $answer);
 
@@ -212,8 +216,10 @@ function lesson_save_question_options($question, $lesson) {
                         $answer->score = 1;
                     }
                     // end Replace
-                    $answer->answer   = $dataanswer;
-                    $answer->response = $question->feedback[$key];
+                    $answer->answer   = $dataanswer['text'];
+                    $answer->answerformat   = $dataanswer['format'];
+                    $answer->response = $question->feedback[$key]['text'];
+                    $answer->responseformat = $question->feedback[$key]['format'];
                     $answer->id = $DB->insert_record("lesson_answers", $answer);
                     // for Sanity checks
                     if ($question->fraction[$key] > 0) {
@@ -268,7 +274,8 @@ function lesson_save_question_options($question, $lesson) {
                 $answertext = $question->subanswers[$key];
                 if (!empty($questiontext) and !empty($answertext)) {
                     $answer = clone($defaultanswer);
-                    $answer->answer = $questiontext;
+                    $answer->answer = $questiontext['text'];
+                    $answer->answerformat   = $questiontext['format'];
                     $answer->response   = $answertext;
                     if ($i == 0) {
                         // first answer contains the correct answer jump
@@ -330,7 +337,9 @@ class qformat_default {
             return false;
         }
 
-        echo $OUTPUT->notification(get_string('importcount', 'lesson', sizeof($questions)));
+        //Avoid category as question type
+        echo $OUTPUT->notification(get_string('importcount', 'lesson',
+                $this->count_questions($questions)), 'notifysuccess');
 
         $count = 0;
 
@@ -338,6 +347,9 @@ class qformat_default {
 
         foreach ($questions as $question) {   // Process and store each question
             switch ($question->qtype) {
+                //TODO: Bad way to bypass category in data... Quickfix for MDL-27964
+                case 'category':
+                    break;
                 // the good ones
                 case SHORTANSWER :
                 case NUMERICAL :
@@ -346,7 +358,9 @@ class qformat_default {
                 case MATCH :
                     $count++;
 
-                    echo "<hr><p><b>$count</b>. ".$question->questiontext."</p>";
+                    //Show nice formated question in one line.
+                    echo "<hr><p><b>$count</b>. ".$this->format_question_text($question)."</p>";
+
                     $newpage = new stdClass;
                     $newpage->lessonid = $lesson->id;
                     $newpage->qtype = $this->qtypeconvert[$question->qtype];
@@ -436,6 +450,27 @@ class qformat_default {
         return true;
     }
 
+    /**
+     * Count all non-category questions in the questions array.
+     *
+     * @param array questions An array of question objects.
+     * @return int The count.
+     *
+     */
+    protected function count_questions($questions) {
+        $count = 0;
+        if (!is_array($questions)) {
+            return $count;
+        }
+        foreach ($questions as $question) {
+            if (!is_object($question) || !isset($question->qtype) ||
+                    ($question->qtype == 'category')) {
+                continue;
+            }
+            $count++;
+        }
+        return $count;
+    }
 
     function readdata($filename) {
     /// Returns complete file with an array, one item per line
@@ -505,7 +540,7 @@ class qformat_default {
 
         $question = new stdClass();
         $question->shuffleanswers = get_config('quiz', 'shuffleanswers');
-        $question->defaultgrade = 1;
+        $question->defaultmark = 1;
         $question->image = "";
         $question->usecase = 0;
         $question->multiplier = array();
@@ -519,6 +554,11 @@ class qformat_default {
         $question->qoption = 0;
         $question->layout = 1;
 
+        // this option in case the questiontypes class wants
+        // to know where the data came from
+        $question->export_process = true;
+        $question->import_process = true;
+
         return $question;
     }
 
@@ -529,6 +569,16 @@ class qformat_default {
         return true;
     }
 
+    /**
+     * Convert the question text to plain text, so it can safely be displayed
+     * during import to let the user see roughly what is going on.
+     */
+    protected function format_question_text($question) {
+        $formatoptions = new stdClass();
+        $formatoptions->noclean = true;
+        return html_to_text(format_text($question->questiontext,
+                $question->questiontextformat, $formatoptions), 0, false);
+    }
 }
 
 
index 6d2921f..0b00e20 100644 (file)
@@ -66,9 +66,13 @@ if ($data = $mform->get_data()) {
 
     require_sesskey();
 
-    if (!$importfile = $mform->get_importfile_name()) {
-        print_error('uploadproblem', 'moodle');
-        }
+    $realfilename = $mform->get_new_filename('questionfile');
+    //TODO: Leave all imported questions in Questionimport for now.
+    $importfile = "{$CFG->dataroot}/temp/questionimport/{$realfilename}";
+    make_upload_directory('temp/questionimport');
+    if (!$result = $mform->save_file('questionfile', $importfile, true)) {
+        throw new moodle_exception('uploadproblem');
+    }
 
     $formatclass = 'qformat_'.$data->format;
     $formatclassfile = $CFG->dirroot.'/question/format/'.$data->format.'/format.php';
@@ -102,4 +106,4 @@ if ($data = $mform->get_data()) {
     $mform->display();
 }
 
-echo $OUTPUT->footer();
+echo $OUTPUT->footer();
\ No newline at end of file
index 4bd93d4..765d565 100644 (file)
@@ -48,30 +48,49 @@ class lesson_import_form extends moodleform {
         $mform->setType('format', 'text');
         $mform->addRule('format', null, 'required');
 
-        $mform->addElement('file', 'newfile', get_string('upload'), array('size'=>'50'));
-        $mform->addRule('newfile', null, 'required');
-
-        $this->add_action_buttons(null, get_string("uploadthisfile"));
+        //Using filemanager as filepicker
+        $mform->addElement('filepicker', 'questionfile', get_string('upload'));
+        $mform->addRule('questionfile', null, 'required', null, 'client');
 
+        $this->add_action_buttons(null, get_string("import"));
     }
 
-    public function get_importfile_name(){
-        if ($this->is_submitted() and $this->is_validated()) {
-            // return the temporary filename to process
-            return $_FILES['newfile']['tmp_name'];
-        }else{
-            return  NULL;
+    /**
+     * Checks that a file has been uploaded, and that it is of a plausible type.
+     * @param array $data the submitted data.
+     * @param array $errors the errors so far.
+     * @return array the updated errors.
+     */
+    protected function validate_uploaded_file($data, $errors) {
+        global $CFG;
+
+        if (empty($data['questionfile'])) {
+            $errors['questionfile'] = get_string('required');
+            return $errors;
+        }
+
+        $files = $this->get_draft_files('questionfile');
+        if (count($files) < 1) {
+            $errors['questionfile'] = get_string('required');
+            return $errors;
         }
-    }
 
-    public function get_importfile_realname(){
-        if ($this->is_submitted() and $this->is_validated()) {
-            // return the temporary filename to process
-            // TODO change this to use the files API properly.
-            return $_FILES['newfile']['name'];
-        }else{
-            return  NULL;
+        $formatfile = $CFG->dirroot.'/question/format/'.$data['format'].'/format.php';
+        if (!is_readable($formatfile)) {
+            throw new moodle_exception('formatnotfound', 'lesson', '', $data['format']);
         }
+
+        require_once($formatfile);
+
+        $classname = 'qformat_' . $data['format'];
+        $qformat = new $classname();
+
+        return $errors;
     }
 
+    public function validation($data, $files) {
+        $errors = parent::validation($data, $files);
+        $errors = $this->validate_uploaded_file($data, $errors);
+        return $errors;
+    }
 }
\ No newline at end of file
index abc853a..372cf8b 100644 (file)
@@ -109,6 +109,7 @@ $string['confirmdeletionofthispage'] = 'Confirm deletion of this page';
 $string['congratulations'] = 'Congratulations - end of lesson reached';
 $string['continue'] = 'Continue';
 $string['continuetoanswer'] = 'Continue to change answers.';
+$string['continuetonextpage'] = 'Continue to next page.';
 $string['correctanswerjump'] = 'Correct answer jump';
 $string['correctanswerscore'] = 'Correct answer score';
 $string['correctresponse'] = 'Correct response';
@@ -166,11 +167,13 @@ $string['essayemailsubject'] = 'Your grade for {$a} question';
 $string['essays'] = 'Essays';
 $string['essayscore'] = 'Essay score';
 $string['fileformat'] = 'File format';
+$string['finish'] = 'Finish';
 $string['firstanswershould'] = 'First answer should jump to the "Correct" page';
 $string['firstwrong'] = 'Unfortunately you cannot earn this one point, because your response was not correct.  Would you like to keep guessing, just for the sheer joy of learning (but for no point credit)?';
 $string['flowcontrol'] = 'Flow control';
 $string['full'] = 'Expanded';
 $string['general'] = 'General';
+$string['gotoendoflesson'] = 'Go to the end of the lesson';
 $string['grade'] = 'Grade';
 $string['gradebetterthan'] = 'Grade better than (&#37;)';
 $string['gradebetterthanerror'] = 'Earn a grade better than {$a} percent';
@@ -378,6 +381,7 @@ $string['studentattemptlesson'] = '{$a->lastname}, {$a->firstname}\'s attempt nu
 $string['studentname'] = '{$a} Name';
 $string['studentoneminwarning'] = 'Warning: You have 1 minute or less to finish the lesson.';
 $string['studentresponse'] = '{$a}\'s response';
+$string['submit'] = 'Submit';
 $string['submitname'] = 'Submit name';
 $string['teacherjumpwarning'] = 'An {$a->cluster} jump or an {$a->unseen} jump is being used in this lesson.  The next page jump will be used instead.  Login as a student to test these jumps.';
 $string['teacherongoingwarning'] = 'Ongoing score is only displayed for student.  Login as a student to test ongoing score';
index cfb1bbc..1b4906e 100644 (file)
@@ -989,7 +989,7 @@ function lesson_get_file_info($browser, $areas, $course, $cm, $context, $fileare
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function lesson_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function lesson_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-lesson-*'=>get_string('page-mod-lesson-x', 'lesson'));
     return $module_pagetype;
 }
index 84a8661..f26f1be 100644 (file)
@@ -1961,13 +1961,15 @@ abstract class lesson_page extends lesson_base {
                     $attempt->retry = $nretakes - 1; // they are going through on review, $nretakes will be too high
                 }
 
-                $DB->insert_record("lesson_attempts", $attempt);
+                if ($this->lesson->retake || (!$this->lesson->retake && $nretakes == 0)) {
+                    $DB->insert_record("lesson_attempts", $attempt);
+                }
                 // "number of attempts remaining" message if $this->lesson->maxattempts > 1
                 // displaying of message(s) is at the end of page for more ergonomic display
                 if (!$result->correctanswer && ($result->newpageid == 0)) {
                     // wrong answer and student is stuck on this page - check how many attempts
                     // the student has had at this page/question
-                    $nattempts = $DB->count_records("lesson_attempts", array("pageid"=>$this->properties->id, "userid"=>$USER->id, "retry" => $nretakes));
+                    $nattempts = $DB->count_records("lesson_attempts", array("pageid"=>$this->properties->id, "userid"=>$USER->id, "retry" => $attempt->retry));
                     // retreive the number of attempts left counter for displaying at bottom of feedback page
                     if ($nattempts >= $this->lesson->maxattempts) {
                         if ($this->lesson->maxattempts > 1) { // don't bother with message if only one attempt
index 2f7d4f9..b1c8136 100644 (file)
@@ -51,14 +51,14 @@ class lesson_page_type_essay extends lesson_page {
     public function display($renderer, $attempt) {
         global $PAGE, $CFG, $USER;
 
-        $mform = new lesson_display_answer_form_essay($CFG->wwwroot.'/mod/lesson/continue.php', array('contents'=>$this->get_contents()));
+        $mform = new lesson_display_answer_form_essay($CFG->wwwroot.'/mod/lesson/continue.php', array('contents'=>$this->get_contents(), 'lessonid'=>$this->lesson->id));
 
         $data = new stdClass;
         $data->id = $PAGE->cm->id;
         $data->pageid = $this->properties->id;
         if (isset($USER->modattempts[$this->lesson->id])) {
             $essayinfo = unserialize($attempt->useranswer);
-            $data->answer = array('text'=>$essayinfo->answer, 'format'=>FORMAT_HTML);
+            $data->answer = $essayinfo->answer;
         }
         $mform->set_data($data);
         return $mform->display();
@@ -252,6 +252,20 @@ class lesson_display_answer_form_essay extends moodleform {
         $mform = $this->_form;
         $contents = $this->_customdata['contents'];
 
+        $hasattempt = false;
+        $attrs = '';
+        $useranswer = '';
+        $useranswerraw = '';
+        if (isset($this->_customdata['lessonid'])) {
+            $lessonid = $this->_customdata['lessonid'];
+            if (isset($USER->modattempts[$lessonid]->useranswer) && !empty($USER->modattempts[$lessonid]->useranswer)) {
+                $attrs = array('disabled' => 'disabled');
+                $hasattempt = true;
+                $useranswer = unserialize($USER->modattempts[$lessonid]->useranswer);
+                $useranswer = htmlspecialchars_decode($useranswer->answer, ENT_QUOTES);
+            }
+        }
+
         $mform->addElement('header', 'pageheader');
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
@@ -266,10 +280,16 @@ class lesson_display_answer_form_essay extends moodleform {
         $mform->addElement('hidden', 'pageid');
         $mform->setType('pageid', PARAM_INT);
 
-        $mform->addElement('editor', 'answer', get_string('youranswer', 'lesson'), null, null);
-        $mform->setType('answer', PARAM_RAW);
-
-        $this->add_action_buttons(null, get_string("pleaseenteryouranswerinthebox", "lesson"));
+        if ($hasattempt) {
+            $mform->addElement('hidden', 'answer', $useranswerraw);
+            $mform->setType('answer', PARAM_CLEANHTML);
+            $mform->addElement('html', $OUTPUT->container(get_string('youranswer', 'lesson'), 'youranswer'));
+            $mform->addElement('html', $OUTPUT->container($useranswer, 'reviewessay'));
+            $this->add_action_buttons(null, get_string("nextpage", "lesson"));
+        } else {
+            $mform->addElement('editor', 'answer', get_string('youranswer', 'lesson'), null, null);
+            $mform->setType('answer', PARAM_RAW);
+            $this->add_action_buttons(null, get_string("submit", "lesson"));
+        }
     }
-
 }
index 3e40c63..e9ffa09 100644 (file)
@@ -61,7 +61,13 @@ class lesson_page_type_matching extends lesson_page {
     protected function make_answer_form($attempt=null) {
         global $USER, $CFG;
         // don't shuffle answers (could be an option??)
-        $answers = array_slice($this->get_answers(), 2);
+        $getanswers = array_slice($this->get_answers(), 2);
+
+        $answers = array();
+        foreach ($getanswers as $getanswer) {
+            $answers[$getanswer->id] = $getanswer;
+        }
+
         $responses = array();
         foreach ($answers as $answer) {
             // get all the response
@@ -487,6 +493,13 @@ class lesson_display_answer_form_matching extends moodleform {
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
 
+        $hasattempt = false;
+        $disabled = '';
+        if (isset($useranswers) && !empty($useranswers)) {
+            $hasattempt = true;
+            $disabled = array('disabled' => 'disabled');
+        }
+
         $options = new stdClass;
         $options->para = false;
         $options->noclean = true;
@@ -501,19 +514,28 @@ class lesson_display_answer_form_matching extends moodleform {
         foreach ($answers as $answer) {
             $mform->addElement('html', '<div class="answeroption">');
             if ($answer->response != NULL) {
-                $mform->addElement('select', 'response['.$answer->id.']', format_text($answer->answer,$answer->answerformat,$options), $responseoptions);
-                $mform->setType('response['.$answer->id.']', PARAM_TEXT);
-                if (isset($USER->modattempts[$lessonid])) {
-                    $mform->setDefault('response['.$answer->id.']', htmlspecialchars(trim($answers[$useranswers[$i]]->response))); //TODO: this is suspicious
+                $responseid = 'response['.$answer->id.']';
+                if ($hasattempt) {
+                    $responseid = 'response_'.$answer->id;
+                    $mform->addElement('hidden', 'response['.$answer->id.']', htmlspecialchars(trim($answers[$useranswers[$i]]->response)));
+                    $mform->setType('response['.$answer->id.']', PARAM_TEXT);
+                }
+                $mform->addElement('select', $responseid, format_text($answer->answer,$answer->answerformat,$options), $responseoptions, $disabled);
+                $mform->setType($responseid, PARAM_TEXT);
+                if ($hasattempt) {
+                    $mform->setDefault($responseid, htmlspecialchars(trim($answers[$useranswers[$i]]->response))); //TODO: this is suspicious
                 } else {
-                    $mform->setDefault('response['.$answer->id.']', 'answeroption');
+                    $mform->setDefault($responseid, 'answeroption');
                 }
             }
             $mform->addElement('html', '</div>');
             $i++;
         }
-
-        $this->add_action_buttons(null, get_string("pleasematchtheabovepairs", "lesson"));
+        if ($hasattempt) {
+            $this->add_action_buttons(null, get_string("nextpage", "lesson"));
+        } else {
+            $this->add_action_buttons(null, get_string("submit", "lesson"));
+        }
     }
 
 }
index f29268f..078af89 100644 (file)
@@ -490,6 +490,13 @@ class lesson_display_answer_form_multichoice_singleanswer extends moodleform {
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
 
+        $hasattempt = false;
+        $disabled = '';
+        if (isset($USER->modattempts[$lessonid]) && !empty($USER->modattempts[$lessonid])) {
+            $hasattempt = true;
+            $disabled = array('disabled' => 'disabled');
+        }
+
         $options = new stdClass;
         $options->para = false;
         $options->noclean = true;
@@ -503,16 +510,20 @@ class lesson_display_answer_form_multichoice_singleanswer extends moodleform {
         $i = 0;
         foreach ($answers as $answer) {
             $mform->addElement('html', '<div class="answeroption">');
-            $mform->addElement('radio','answerid',null,format_text($answer->answer, $answer->answerformat, $options),$answer->id);
+            $mform->addElement('radio','answerid',null,format_text($answer->answer, $answer->answerformat, $options),$answer->id, $disabled);
             $mform->setType('answer'.$i, PARAM_INT);
-            if (isset($USER->modattempts[$lessonid]) && $answer->id == $USER->modattempts[$lessonid]->answerid) {
-                $mform->setDefault('answerid', true);
+            if ($hasattempt && $answer->id == $USER->modattempts[$lessonid]->answerid) {
+                $mform->setDefault('answerid', $USER->modattempts[$lessonid]->answerid);
             }
             $mform->addElement('html', '</div>');
             $i++;
         }
 
-        $this->add_action_buttons(null, get_string("pleasecheckoneanswer", "lesson"));
+        if ($hasattempt) {
+            $this->add_action_buttons(null, get_string("nextpage", "lesson"));
+        } else {
+            $this->add_action_buttons(null, get_string("submit", "lesson"));
+        }
     }
 
 }
index 9e5c0f5..8681fdf 100644 (file)
@@ -50,7 +50,7 @@ class lesson_page_type_shortanswer extends lesson_page {
     }
     public function display($renderer, $attempt) {
         global $USER, $CFG, $PAGE;
-        $mform = new lesson_display_answer_form_shortanswer($CFG->wwwroot.'/mod/lesson/continue.php', array('contents'=>$this->get_contents()));
+        $mform = new lesson_display_answer_form_shortanswer($CFG->wwwroot.'/mod/lesson/continue.php', array('contents'=>$this->get_contents(), 'lessonid'=>$this->lesson->id));
         $data = new stdClass;
         $data->id = $PAGE->cm->id;
         $data->pageid = $this->properties->id;
@@ -328,10 +328,20 @@ class lesson_add_page_form_shortanswer extends lesson_add_page_form_base {
 class lesson_display_answer_form_shortanswer extends moodleform {
 
     public function definition() {
-        global $OUTPUT;
+        global $OUTPUT, $USER;
         $mform = $this->_form;
         $contents = $this->_customdata['contents'];
 
+        $hasattempt = false;
+        $attrs = array('size'=>'50', 'maxlength'=>'200');
+        if (isset($this->_customdata['lessonid'])) {
+            $lessonid = $this->_customdata['lessonid'];
+            if (isset($USER->modattempts[$lessonid]->useranswer)) {
+                $attrs['readonly'] = 'readonly';
+                $hasattempt = true;
+            }
+        }
+
         $mform->addElement('header', 'pageheader');
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
@@ -346,10 +356,14 @@ class lesson_display_answer_form_shortanswer extends moodleform {
         $mform->addElement('hidden', 'pageid');
         $mform->setType('pageid', PARAM_INT);
 
-        $mform->addElement('text', 'answer', get_string('youranswer', 'lesson'), array('size'=>'50', 'maxlength'=>'200'));
+        $mform->addElement('text', 'answer', get_string('youranswer', 'lesson'), $attrs);
         $mform->setType('answer', PARAM_TEXT);
 
-        $this->add_action_buttons(null, get_string("pleaseenteryouranswerinthebox", "lesson"));
+        if ($hasattempt) {
+            $this->add_action_buttons(null, get_string("nextpage", "lesson"));
+        } else {
+            $this->add_action_buttons(null, get_string("submit", "lesson"));
+        }
     }
 
 }
index 61a1a7e..6b8977b 100644 (file)
@@ -303,6 +303,13 @@ class lesson_display_answer_form_truefalse extends moodleform {
 
         $mform->addElement('html', $OUTPUT->container($contents, 'contents'));
 
+        $hasattempt = false;
+        $disabled = '';
+        if (isset($USER->modattempts[$lessonid]) && !empty($USER->modattempts[$lessonid])) {
+            $hasattempt = true;
+            $disabled = array('disabled' => 'disabled');
+        }
+
         $options = new stdClass();
         $options->para = false;
         $options->noclean = true;
@@ -316,16 +323,28 @@ class lesson_display_answer_form_truefalse extends moodleform {
         $i = 0;
         foreach ($answers as $answer) {
             $mform->addElement('html', '<div class="answeroption">');
-            $mform->addElement('radio', 'answerid', null, format_text($answer->answer, $answer->answerformat, $options), $answer->id);
-            $mform->setType('answerid', PARAM_INT);
-            if (isset($USER->modattempts[$lessonid]) && $answer->id == $attempt->answerid) {
-                $mform->setDefault('answerid', true);
+            $ansid = 'answerid';
+            if ($hasattempt) {
+                $ansid = 'answer_id';
+            }
+
+            $mform->addElement('radio', $ansid, null, format_text($answer->answer, $answer->answerformat, $options), $answer->id, $disabled);
+            $mform->setType($ansid, PARAM_INT);
+            if ($hasattempt && $answer->id == $USER->modattempts[$lessonid]->answerid) {
+                $mform->setDefault($ansid, $attempt->answerid);
+                $mform->addElement('hidden', 'answerid', $answer->id);
+                $mform->setType('answerid', PARAM_INT);
             }
             $mform->addElement('html', '</div>');
             $i++;
         }
 
-        $this->add_action_buttons(null, get_string("pleasecheckoneanswer", "lesson"));
+        if ($hasattempt) {
+            $this->add_action_buttons(null, get_string("nextpage", "lesson"));
+        } else {
+            $this->add_action_buttons(null, get_string("submit", "lesson"));
+        }
+
     }
 
 }
index 99028da..fd4541a 100644 (file)
@@ -28,4 +28,5 @@
 /**
  * Style for view.php
  **/
-#page-mod-lesson-view .password-form .submitbutton {display: inline;}
\ No newline at end of file
+#page-mod-lesson-view .password-form .submitbutton {display: inline;}
+.path-mod-lesson .reviewessay {width:40%; border:1px solid #DDDDDD; background-color: #EEEEEE;}
index c82d589..855b755 100644 (file)
@@ -60,6 +60,12 @@ $canmanage = has_capability('mod/lesson:manage', $context);
 
 $lessonoutput = $PAGE->get_renderer('mod_lesson');
 
+$reviewmode = false;
+$userhasgrade = $DB->count_records("lesson_grades", array("lessonid"=>$lesson->id, "userid"=>$USER->id));
+if ($userhasgrade && !$lesson->retake) {
+    $reviewmode = true;
+}
+
 /// Check these for students only TODO: Find a better method for doing this!
 ///     Check lesson availability
 ///     Check for password
@@ -316,11 +322,14 @@ if ($pageid != LESSON_EOL) {
                     $a->minquestions = $lesson->minquestions;
                     $lesson->add_message(get_string('numberofpagesviewednotice', 'lesson', $a));
                 }
-                $lesson->add_message(get_string("numberofcorrectanswers", "lesson", $gradeinfo->earned), 'notify');
+
                 $a = new stdClass;
                 $a->grade = number_format($gradeinfo->grade * $lesson->grade / 100, 1);
                 $a->total = $lesson->grade;
-                $lesson->add_message(get_string('yourcurrentgradeisoutof', 'lesson', $a), 'notify');
+                if (!$reviewmode && !$lesson->retake){
+                    $lesson->add_message(get_string("numberofcorrectanswers", "lesson", $gradeinfo->earned), 'notify');
+                    $lesson->add_message(get_string('yourcurrentgradeisoutof', 'lesson', $a), 'notify');
+                }
             }
         }
     } else {
@@ -356,6 +365,7 @@ if ($pageid != LESSON_EOL) {
                 print_error('cannotfindpreattempt', 'lesson');
             }
             $attempt = end($attempts);
+            $USER->modattempts[$lesson->id] = $attempt;
         } else {
             $attempt = false;
         }
@@ -387,7 +397,7 @@ if ($pageid != LESSON_EOL) {
         echo $OUTPUT->heading(get_string('attempt', 'lesson', $retries));
     }
     /// This calculates and prints the ongoing score
-    if ($lesson->ongoing && !empty($pageid)) {
+    if ($lesson->ongoing && !empty($pageid) && !$reviewmode) {
         echo $lessonoutput->ongoing_score($lesson);
     }
     if ($lesson->displayleft) {
@@ -538,17 +548,18 @@ if ($pageid != LESSON_EOL) {
         // $ntries is decremented above
         if (!$attempts = $lesson->get_attempts($ntries)) {
             $attempts = array();
+            $url = new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id));
+        } else {
+            $firstattempt = current($attempts);
+            $pageid = $firstattempt->pageid;
+            // IF the student wishes to review, need to know the last question page that the student answered.  This will help to make
+            // sure that the student can leave the lesson via pushing the continue button.
+            $lastattempt = end($attempts);
+            $USER->modattempts[$lesson->id] = $lastattempt->pageid;
+
+            $url = new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id, 'pageid'=>$pageid));
         }
-        $firstattempt = current($attempts);
-        $pageid = $firstattempt->pageid;
-        // IF the student wishes to review, need to know the last question page that the student answered.  This will help to make
-        // sure that the student can leave the lesson via pushing the continue button.
-        $lastattempt = end($attempts);
-        $USER->modattempts[$lesson->id] = $lastattempt->pageid;
-
-        $url = new moodle_url('/mod/lesson/view.php', array('id'=>$PAGE->cm->id, 'pageid'=>$pageid));
         $lessoncontent .= html_writer::link($url, get_string('reviewlesson', 'lesson'), array('class' => 'centerpadded lessonbutton standardbutton'));
-
     } elseif ($lesson->modattempts && $canmanage) {
         $lessoncontent .= $lessonoutput->paragraph(get_string("modattemptsnoteacher", "lesson"), 'centerpadded');
     }
index 300051b..2fcd026 100644 (file)
@@ -411,7 +411,7 @@ function page_extend_navigation($navigation, $course, $module, $cm) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function page_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function page_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-page-*'=>get_string('page-mod-page-x', 'page'));
     return $module_pagetype;
 }
index b2ed15b..a80f87c 100644 (file)
@@ -271,27 +271,19 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
     }
 
     protected function process_quiz_attempt($data) {
-        global $DB;
-
         $data = (object)$data;
-        $oldid = $data->id;
-        $olduniqueid = $data->uniqueid;
 
         $data->quiz = $this->get_new_parentid('quiz');
         $data->attempt = $data->attemptnum;
 
-        $data->uniqueid = 0; // filled in later by {@link inform_new_usage_id()}
-
         $data->userid = $this->get_mappingid('user', $data->userid);
 
         $data->timestart = $this->apply_date_offset($data->timestart);
         $data->timefinish = $this->apply_date_offset($data->timefinish);
         $data->timemodified = $this->apply_date_offset($data->timemodified);
 
-        $newitemid = $DB->insert_record('quiz_attempts', $data);
-
-        // Save quiz_attempt->id mapping, because logs use it
-        $this->set_mapping('quiz_attempt', $oldid, $newitemid, false);
+        // The data is actually inserted into the database later in inform_new_usage_id.
+        $this->currentquizattempt = clone($data);
     }
 
     protected function process_quiz_attempt_legacy($data) {
@@ -306,8 +298,16 @@ class restore_quiz_activity_structure_step extends restore_questions_activity_st
 
     protected function inform_new_usage_id($newusageid) {
         global $DB;
-        $DB->set_field('quiz_attempts', 'uniqueid', $newusageid, array('id' =>
-                $this->get_new_parentid('quiz_attempt')));
+
+        $data = $this->currentquizattempt;
+
+        $oldid = $data->id;
+        $data->uniqueid = $newusageid;
+
+        $newitemid = $DB->insert_record('quiz_attempts', $data);
+
+        // Save quiz_attempt->id mapping, because logs use it
+        $this->set_mapping('quiz_attempt', $oldid, $newitemid, false);
     }
 
     protected function after_execute() {
index 865b85c..2bebe24 100644 (file)
@@ -562,6 +562,8 @@ function xmldb_quiz_upgrade($oldversion) {
             ');
 
             if ($oldattempts) {
+                require_once($CFG->dirroot . '/mod/quiz/db/upgradelib.php');
+
                 $pbar = new progress_bar('q15upgrade');
                 $pbar->create();
                 $a = new stdClass();
index 0b458ef..2536814 100644 (file)
@@ -26,6 +26,8 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+require_once($CFG->dirroot . '/mod/quiz/locallib.php');
+
 
 /**
  * Upgrade states for an attempt to Moodle 1.5 model
index 4cf6fcf..3eadb0b 100644 (file)
@@ -1710,7 +1710,7 @@ function mod_quiz_question_pluginfile($course, $context, $component,
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function quiz_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function quiz_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-quiz-*'=>get_string('page-mod-quiz-x', 'quiz'));
     return $module_pagetype;
 }
index 3efca32..0e57182 100644 (file)
@@ -880,7 +880,7 @@ function quiz_question_preview_url($quiz, $question) {
  * @return the HTML for a preview question icon.
  */
 function quiz_question_preview_button($quiz, $question, $label = false) {
-    global $CFG, $COURSE, $OUTPUT;
+    global $CFG, $OUTPUT;
     if (!question_has_capability_on($question, 'use', $question->category)) {
         return '';
     }
index 803c89b..be79a32 100644 (file)
@@ -436,7 +436,7 @@ function resource_pluginfile($course, $cm, $context, $filearea, $args, $forcedow
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function resource_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function resource_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-resource-*'=>get_string('page-mod-resource-x', 'resource'));
     return $module_pagetype;
 }
index bbddc92..b799907 100644 (file)
@@ -1078,7 +1078,7 @@ function scorm_print_overview($courses, &$htmlarray) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function scorm_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function scorm_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-scorm-*'=>get_string('page-mod-scorm-x', 'scorm'));
     return $module_pagetype;
 }
index 67b8987..d1e3bf1 100644 (file)
@@ -696,7 +696,8 @@ function scorm_course_format_display($user,$course) {
     } else {
         if (has_capability('moodle/course:update', $context)) {
             // Create a new activity
-            redirect($CFG->wwwroot.'/course/mod.php?id='.$course->id.'&amp;section=0&sesskey='.sesskey().'&amp;add=scorm');
+            $url = new moodle_url('/course/mod.php', array('id'=>$course->id, 'section'=>'0', 'sesskey'=>sesskey(),'add'=>'scorm'));
+            redirect($url);
         } else {
             echo $OUTPUT->notification('Could not find a scorm course here');
         }
index 9c3d380..bed1fa1 100644 (file)
@@ -871,7 +871,7 @@ function survey_extend_settings_navigation($settings, $surveynode) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function survey_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function survey_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-survey-*'=>get_string('page-mod-survey-x', 'survey'));
     return $module_pagetype;
 }
index 9e43a41..e354511 100644 (file)
@@ -318,7 +318,7 @@ function url_extend_navigation($navigation, $course, $module, $cm) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function url_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function url_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-url-*'=>get_string('page-mod-url-x', 'url'));
     return $module_pagetype;
 }
index 42c8429..7f9a3d6 100644 (file)
@@ -665,7 +665,7 @@ function wiki_comment_validate($comment_param) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function wiki_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function wiki_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array(
         'mod-wiki-*'=>get_string('page-mod-wiki-x', 'wiki'),
         'mod-wiki-view'=>get_string('page-mod-wiki-view', 'wiki'),
index a4d86a3..26880ed 100644 (file)
@@ -1382,7 +1382,7 @@ function workshop_extend_settings_navigation(settings_navigation $settingsnav, n
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function workshop_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function workshop_page_type_list($pagetype, $parentcontext, $currentcontext) {
     $module_pagetype = array('mod-workshop-*'=>get_string('page-mod-workshop-x', 'workshop'));
     return $module_pagetype;
 }
index f01d870..0744211 100644 (file)
@@ -284,6 +284,6 @@ function note_delete_all($courseid) {
  * @param stdClass $parentcontext Block's parent context
  * @param stdClass $currentcontext Current context of block
  */
-function note_pagetypelist($pagetype, $parentcontext, $currentcontext) {
+function note_page_type_list($pagetype, $parentcontext, $currentcontext) {
     return array('notes-*'=>get_string('page-notes-x', 'notes'));
 }
index e749921..cc855cc 100644 (file)
@@ -294,6 +294,9 @@ if ($component === 'blog') {
 // ========================================================================================================================
 } else if ($component === 'user') {
     if ($filearea === 'icon' and $context->contextlevel == CONTEXT_USER) {
+        // XXX: pix_url will initialize $PAGE, so we have to set up context here
+        // this temp hack should be fixed by better solution
+        $PAGE->set_context(get_system_context());
         if (!empty($CFG->forcelogin) and !isloggedin()) {
             // protect images if login required and not logged in;
             // do not use require_login() because it is expensive and not suitable here anyway
index cf266ae..7a78f17 100644 (file)
@@ -26,7 +26,7 @@
 $string['assumingcertainty'] = 'You did not select a certainty. Assuming: {$a}.';
 $string['certainty1'] = 'Not very (less than 67%)';
 $string['certainty2'] = 'Fairly (more than 67%)';
-$string['certainty3'] = 'Very (more than 85%)';
+$string['certainty3'] = 'Very (more than 80%)';
 $string['howcertainareyou'] = 'How certain are you? {$a}';
 $string['markadjustment'] = 'Based on the certainty you expressed, your base mark of {$a->rawmark} was adjusted to {$a->mark}.';
 $string['pluginname'] = 'Deferred feedback with CBM';
index afb8891..d7c082a 100644 (file)
@@ -1152,7 +1152,8 @@ class question_bank_view {
     }
 
     public function preview_question_url($question) {
-        return question_preview_url($question->id);
+        return question_preview_url($question->id, null, null, null, null,
+                $this->contexts->lowest());
     }
 
     /**
index 3a9f50a..0553b4e 100644 (file)
@@ -435,6 +435,7 @@ class qbehaviour_informationitem_converter extends question_behaviour_attempt_up
 
 class qbehaviour_adaptive_converter extends question_behaviour_attempt_updater {
     protected $try;
+    protected $laststepwasatry = false;
     protected $finished = false;
     protected $bestrawgrade = 0;
 
@@ -455,7 +456,7 @@ class qbehaviour_adaptive_converter extends question_behaviour_attempt_updater {
 
     protected function process0($step, $state) {
         $this->try = 1;
-        $step->data['-_try'] = $this->try;
+        $this->laststepwasatry = false;
         parent::process0($step, $state);
     }
 
@@ -471,6 +472,7 @@ class qbehaviour_adaptive_converter extends question_behaviour_attempt_updater {
             $step->fraction = $state->grade / $this->question->maxmark;
         }
 
+        $this->laststepwasatry = false;
         parent::process2($step, $state);
     }
 
@@ -488,8 +490,9 @@ class qbehaviour_adaptive_converter extends question_behaviour_attempt_updater {
 
         $this->bestrawgrade = max($state->raw_grade, $this->bestrawgrade);
 
-        $this->try += 1;
         $step->data['-_try'] = $this->try;
+        $this->try += 1;
+        $this->laststepwasatry = true;
         if ($this->question->maxmark > 0) {
             $step->data['-_rawfraction'] = $state->raw_grade / $this->question->maxmark;
         } else {
@@ -524,6 +527,9 @@ class qbehaviour_adaptive_converter extends question_behaviour_attempt_updater {
         }
 
         $step->data['-finish'] = 1;
+        if ($this->laststepwasatry) {
+            $this->try -= 1;
+        }
         $step->data['-_try'] = $this->try;
         if ($this->question->maxmark > 0) {
             $step->data['-_rawfraction'] = $state->raw_grade / $this->question->maxmark;
index e6085a6..ea24399 100644 (file)
@@ -37,19 +37,36 @@ require_once(dirname(__FILE__) . '/previewlib.php');
 // Get and validate question id.
 $id = required_param('id', PARAM_INT);
 $question = question_bank::load_question($id);
-require_login();
-$category = $DB->get_record('question_categories',
-        array('id' => $question->category), '*', MUST_EXIST);
-question_require_capability_on($question, 'use');
 $PAGE->set_pagelayout('popup');
-$PAGE->set_context(get_context_instance_by_id($category->contextid));
+
+// Were we given a particular context to run the question in?
+// This affects things like filter settings, or forced theme or language.
+if ($cmid = optional_param('cmid', 0, PARAM_INT)) {
+    $cm = get_coursemodule_from_id(false, $cmid);
+    require_login($cm->course, false, $cm);
+    $context = get_context_instance(CONTEXT_MODULE, $cmid);
+
+} else if ($courseid = optional_param('courseid', 0, PARAM_INT)) {
+    require_login($courseid);
+    $context = get_context_instance(CONTEXT_COURSE, $courseid);
+
+} else {
+    require_login();
+    $category = $DB->get_record('question_categories',
+            array('id' => $question->category), '*', MUST_EXIST);
+    $context = get_context_instance_by_id($category->contextid);
+    $PAGE->set_context($context);
+    // Note that in the other cases, require_login will set the correct page context.
+}
+question_require_capability_on($question, 'use');
 
 // Get and validate display options.
 $maxvariant = $question->get_num_variants();
 $options = new question_preview_options($question);
 $options->load_user_defaults();
 $options->set_from_request();
-$PAGE->set_url(question_preview_url($id, $options->behaviour, $options->maxmark, $options));
+$PAGE->set_url(question_preview_url($id, $options->behaviour, $options->maxmark,
+        $options, $options->variant, $context));
 
 // Get and validate exitsing preview, or start a new one.
 $previewid = optional_param('previewid', 0, PARAM_INT);
@@ -63,7 +80,7 @@ if ($previewid) {
     } catch (Exception $e) {
         print_error('submissionoutofsequencefriendlymessage', 'question',
                 question_preview_url($question->id, $options->behaviour,
-                $options->maxmark, $options), null, $e);
+                $options->maxmark, $options, $options->variant, $context), null, $e);
     }
     $slot = $quba->get_first_question_number();
     $usedquestion = $quba->get_question($slot);
@@ -74,8 +91,8 @@ if ($previewid) {
     $options->variant = $quba->get_variant($slot);
 
 } else {
-    $quba = question_engine::make_questions_usage_by_activity('core_question_preview',
-            get_context_instance_by_id($category->contextid));
+    $quba = question_engine::make_questions_usage_by_activity(
+            'core_question_preview', $context);
     $quba->set_preferred_behaviour($options->behaviour);
     $slot = $quba->add_question($question, $options->maxmark);
 
@@ -97,8 +114,8 @@ $options->behaviour = $quba->get_preferred_behaviour();
 $options->maxmark = $quba->get_question_max_mark($slot);
 
 // Create the settings form, and initialise the fields.
-$optionsform = new preview_options_form(new moodle_url('/question/preview.php',
-        array('id' => $question->id)), array('quba' => $quba, 'maxvariant' => $maxvariant));
+$optionsform = new preview_options_form(question_preview_form_url($question->id, $context),
+        array('quba' => $quba, 'maxvariant' => $maxvariant));
 $optionsform->set_data($options);
 
 // Process change of settings, if that was requested.
@@ -108,16 +125,16 @@ if ($newoptions = $optionsform->get_submitted_data()) {
     if (!isset($newoptions->variant)) {
         $newoptions->variant = $options->variant;
     }
-    restart_preview($previewid, $question->id, $newoptions);
+    restart_preview($previewid, $question->id, $newoptions, $context);
 }
 
 // Prepare a URL that is used in various places.
-$actionurl = question_preview_action_url($question->id, $quba->get_id(), $options);
+$actionurl = question_preview_action_url($question->id, $quba->get_id(), $options, $context);
 
 // Process any actions from the buttons at the bottom of the form.
 if (data_submitted() && confirm_sesskey()) {
     if (optional_param('restart', false, PARAM_BOOL)) {
-        restart_preview($previewid, $question->id, $options);
+        restart_preview($previewid, $question->id, $options, $context);
 
     } else if (optional_param('fill', null, PARAM_BOOL)) {
         $correctresponse = $quba->get_correct_response($slot);
index 6e34333..0978e87 100644 (file)
@@ -230,10 +230,6 @@ function question_preview_question_pluginfile($course, $context, $component,
 
     $quba = question_engine::load_questions_usage_by_activity($qubaid);
 
-    if ($quba->get_owning_context()->id != $context->id) {
-        send_file_not_found();
-    }
-
     if (!question_has_capability_on($quba->get_question($slot), 'use')) {
         send_file_not_found();
     }
@@ -267,22 +263,46 @@ function question_preview_question_pluginfile($course, $context, $component,
  * @param question_preview_options $options the options in use.
  */
 function question_preview_action_url($questionid, $qubaid,
-        question_preview_options $options) {
+        question_preview_options $options, $context) {
     $params = array(
         'id' => $questionid,
         'previewid' => $qubaid,
     );
+    if ($context->contextlevel == CONTEXT_MODULE) {
+        $params['cmid'] = $context->instanceid;
+    } else if ($context->contextlevel == CONTEXT_COURSE) {
+        $params['courseid'] = $context->instanceid;
+    }
     $params = array_merge($params, $options->get_url_params());
     return new moodle_url('/question/preview.php', $params);
 }
 
+/**
+ * The the URL to use for actions relating to this preview.
+ * @param int $questionid the question being previewed.
+ * @param int $qubaid the id of the question usage for this preview.
+ * @param question_preview_options $options the options in use.
+ */
+function question_preview_form_url($questionid, $context) {
+    $params = array(
+        'id' => $questionid,
+    );
+    if ($context->contextlevel == CONTEXT_MODULE) {
+        $params['cmid'] = $context->instanceid;
+    } else if ($context->contextlevel == CONTEXT_COURSE) {
+        $params['courseid'] = $context->instanceid;
+    }
+    return new moodle_url('/question/preview.php', $params);
+}
+
 /**
  * Delete the current preview, if any, and redirect to start a new preview.
  * @param int $previewid
  * @param int $questionid
  * @param object $displayoptions
+ * @param object $context
  */
-function restart_preview($previewid, $questionid, $displayoptions) {
+function restart_preview($previewid, $questionid, $displayoptions, $context) {
     global $DB;
 
     if ($previewid) {
@@ -291,5 +311,5 @@ function restart_preview($previewid, $questionid, $displayoptions) {
         $transaction->allow_commit();
     }
     redirect(question_preview_url($questionid, $displayoptions->behaviour,
-            $displayoptions->maxmark, $displayoptions, $displayoptions->variant));
+            $displayoptions->maxmark, $displayoptions, $displayoptions->variant, $context));
 }
index 315dd3c..6a3f315 100644 (file)
@@ -219,7 +219,7 @@ Remember to type a unit.',
                     'fraction' => null,
                     'timecreated' => 1305830650,
                     'userid' => 4,
-                    'data' => array('-_try' => 1, '_separators' => '.$,',
+                    'data' => array('_separators' => '.$,',
                             '_var_a' => '7.5', '_var_b' => '4.9'),
                 ),
                 1 => (object) array(
@@ -442,7 +442,7 @@ Remember to type a unit.',
                     'fraction' => null,
                     'timecreated' => 1305830661,
                     'userid' => 4,
-                    'data' => array('-_try' => 1, '_separators' => '.$,',
+                    'data' => array('_separators' => '.$,',
                             '_var_a' => '5.1', '_var_b' => '4.5'),
                 ),
                 1 => (object) array(
@@ -451,7 +451,7 @@ Remember to type a unit.',
                     'fraction' => 0.5,
                     'timecreated' => 1305830714,
                     'userid' => 4,
-                    'data' => array('answer' => 9.6, '-_try' => 2,
+                    'data' => array('answer' => 9.6, '-_try' => 1,
                             '-_rawfraction' => 0.5, '-submit' => 1),
                 ),
                 2 => (object) array(
@@ -460,7 +460,7 @@ Remember to type a unit.',
                     'fraction' => 0.9,
                     'timecreated' => 1305830722,
                     'userid' => 4,
-                    'data' => array('answer' => '9.6 m', '-_try' => 3,
+                    'data' => array('answer' => '9.6 m', '-_try' => 2,
                             '-_rawfraction' => 1, '-submit' => 1),
                 ),
                 3 => (object) array(
@@ -469,7 +469,7 @@ Remember to type a unit.',
                     'fraction' => 0.9,
                     'timecreated' => 1305830722,
                     'userid' => 4,
-                    'data' => array('answer' => '9.6 m', '-_try' => 3,
+                    'data' => array('answer' => '9.6 m', '-_try' => 2,
                             '-_rawfraction' => 1, '-finish' => 1),
                 ),
             ),
@@ -672,7 +672,7 @@ Remember to type a unit.',
                     'fraction' => null,
                     'timecreated' => 1305830744,
                     'userid' => 3,
-                    'data' => array('-_try' => 1, '_separators' => '.$,',
+                    'data' => array('_separators' => '.$,',
                             '_var_a' => '9.9', '_var_b' => '2.5'),
                 ),
                 1 => (object) array(
@@ -681,7 +681,7 @@ Remember to type a unit.',
                     'fraction' => 0,
                     'timecreated' => 1305830775,
                     'userid' => 3,
-                    'data' => array('answer' => '123 cm', '-_try' => 2,
+                    'data' => array('answer' => '123 cm', '-_try' => 1,
                             '-_rawfraction' => 0, '-submit' => 1),
                 ),
                 2 => (object) array(
index 36fe371..c3db14c 100644 (file)
@@ -207,7 +207,7 @@ class qtype_calculated_qe2_attempt_updater extends question_qtype_attempt_update
      * @param $x
      */
     public function format_float($x, $length = null, $format = null) {
-        if (!is_null($format) && !is_null($format)) {
+        if (!is_null($length) && !is_null($format)) {
             if ($format == 1) {
                 // Decimal places.
                 $x = sprintf('%.' . $length . 'F', $x);
index 66f2e9a..b89b9c8 100644 (file)
@@ -310,7 +310,7 @@ class qtype_calculated_variable_substituter {
      * @param $x
      */
     public function format_float($x, $length = null, $format = null) {
-        if (!is_null($format) && !is_null($format)) {
+        if (!is_null($length) && !is_null($format)) {
             if ($format == 1) {
                 // Decimal places.
                 $x = sprintf('%.' . $length . 'F', $x);
index ba7a442..50b506d 100644 (file)
@@ -242,8 +242,7 @@ class qtype_calculatedmulti_attempt_upgrader_test extends question_attempt_upgra
                     'fraction' => null,
                     'timecreated' => 1305830650,
                     'userid' => 4,
-                    'data' => array('-_try' => 1,
-                            '_order' => '24,26,27,25', '_var_a' => '4.3', '_var_b' => '5.4'),
+                    'data' => array('_order' => '24,26,27,25', '_var_a' => '4.3', '_var_b' => '5.4'),
                 ),
                 1 => (object) array(
                     'sequencenumber' => 1,
@@ -476,8 +475,7 @@ class qtype_calculatedmulti_attempt_upgrader_test extends question_attempt_upgra
                     'fraction' => null,
                     'timecreated' => 1305830661,
                     'userid' => 4,
-                    'data' => array('-_try' => 1,
-                            '_order' => '25,24,27,26', '_var_a' => '3.7', '_var_b' => '6.0'),
+                    'data' => array('_order' => '25,24,27,26', '_var_a' => '3.7', '_var_b' => '6.0'),
                 ),
                 1 => (object) array(
                     'sequencenumber' => 1,
@@ -485,7 +483,7 @@ class qtype_calculatedmulti_attempt_upgrader_test extends question_attempt_upgra
                     'fraction' => 1,
                     'timecreated' => 1305830699,
                     'userid' => 4,
-                    'data' => array('answer' => '0', '-submit' => 1, '-_try' => 2, '-_rawfraction' => 1),
+                    'data' => array('answer' => '0', '-submit' => 1, '-_try' => 1, '-_rawfraction' => 1),
                 ),
                 2 => (object) array(
                     'sequencenumber' => 2,
@@ -493,7 +491,7 @@ class qtype_calculatedmulti_attempt_upgrader_test extends question_attempt_upgra
                     'fraction' => 1,
                     'timecreated' => 1305830699,
                     'userid' => 4,
-                    'data' => array('answer' => '0', '-finish' => 1, '-_try' => 2, '-_rawfraction' => 1),
+                    'data' => array('answer' => '0', '-finish' => 1, '-_try' => 1, '-_rawfraction' => 1),
                 ),
             ),
         );
@@ -754,8 +752,7 @@ class qtype_calculatedmulti_attempt_upgrader_test extends question_attempt_upgra
                     'fraction' => null,
                     'timecreated' => 1305830744,
                     'userid' => 3,
-                    'data' => array('-_try' => 1,
-                            '_order' => '26,24,25,27', '_var_a' => '4.4', '_var_b' => '8.2'),
+                    'data' => array('_order' => '26,24,25,27', '_var_a' => '4.4', '_var_b' => '8.2'),
                 ),
                 1 => (object) array(
                     'sequencenumber' => 1,
@@ -763,7 +760,7 @@ class qtype_calculatedmulti_attempt_upgrader_test extends question_attempt_upgra
                     'fraction' => 0,
                     'timecreated' => 1305830759,
                     'userid' => 3,
-                    'data' => array('answer' => '3', '-submit' => 1, '-_try' => 2, '-_rawfraction' => 0),
+                    'data' => array('answer' => '3', '-submit' => 1, '-_try' => 1, '-_rawfraction' => 0),
                 ),
                 2 => (object) array(
                     'sequencenumber' => 2,
@@ -771,7 +768,7 @@ class qtype_calculatedmulti_attempt_upgrader_test extends question_attempt_upgra
                     'fraction' => 0,
                     'timecreated' => 1305830761,
                     'userid' => 3,
-                    'data' => array('answer' => '1', '-submit' => 1, '-_try' => 3, '-_rawfraction' => 0),
+                    'data' => array('answer' => '1', '-submit' => 1, '-_try' => 2, '-_rawfraction' => 0),
                 ),
                 3 => (object) array(
                     'sequencenumber' => 3,
@@ -779,7 +776,7 @@ class qtype_calculatedmulti_attempt_upgrader_test extends question_attempt_upgra
                     'fraction' => 0,
                     'timecreated' => 1305830764,
                     'userid' => 3,
-                    'data' => array('answer' => '0', '-submit' => 1, '-_try' => 4, '-_rawfraction' => 0),
+                    'data' => array('answer' => '0', '-submit' => 1, '-_try' => 3, '-_rawfraction' => 0),
                 ),
                 4 => (object) array(
                     'sequencenumber' => 4,
@@ -787,7 +784,7 @@ class qtype_calculatedmulti_attempt_upgrader_test extends question_attempt_upgra
                     'fraction' => 0.7,
                     'timecreated' => 1305830766,
                     'userid' => 3,
-                    'data' => array('answer' => '2', '-submit' => 1, '-_try' => 5, '-_rawfraction' => 1),
+                    'data' => array('answer' => '2', '-submit' => 1, '-_try' => 4, '-_rawfraction' => 1),
                 ),
                 5 => (object) array(
                     'sequencenumber' => 5,
@@ -795,7 +792,7 @@ class qtype_calculatedmulti_attempt_upgrader_test extends question_attempt_upgra
                     'fraction' => 0.7,
                     'timecreated' => 1305830768,
                     'userid' => 3,
-                    'data' => array('answer' => '1', '-submit' => 1, '-_try' => 6, '-_rawfraction' => 0),
+                    'data' => array('answer' => '1', '-submit' => 1, '-_try' => 5, '-_rawfraction' => 0),
                 ),
             ),
         );
index 5bd7579..8dd51ba 100644 (file)
@@ -231,7 +231,7 @@ class qtype_calculatedmulti_qe2_attempt_updater extends question_qtype_attempt_u
      * @param $x
      */
     public function format_float($x, $length = null, $format = null) {
-        if (!is_null($format) && !is_null($format)) {
+        if (!is_null($length) && !is_null($format)) {
             if ($format == 1) {
                 // Decimal places.
                 $x = sprintf('%.' . $length . 'F', $x);
index a98b7ce..885ed19 100644 (file)
@@ -206,7 +206,7 @@ class qtype_calculatedsimple_attempt_upgrader_test extends question_attempt_upgr
                     'fraction' => null,
                     'timecreated' => 1305830650,
                     'userid' => 4,
-                    'data' => array('-_try' => 1, '_separators' => '.$,',
+                    'data' => array('_separators' => '.$,',
                             '_var_a' => '3', '_var_b' => '6'),
                 ),
                 1 => (object) array(
@@ -416,7 +416,7 @@ class qtype_calculatedsimple_attempt_upgrader_test extends question_attempt_upgr
                     'fraction' => null,
                     'timecreated' => 1305830661,
                     'userid' => 4,
-                    'data' => array('-_try' => 1, '_separators' => '.$,',
+                    'data' => array('_separators' => '.$,',
                             '_var_a' => '6.4', '_var_b' => '9'),
                 ),
                 1 => (object) array(
@@ -425,7 +425,7 @@ class qtype_calculatedsimple_attempt_upgrader_test extends question_attempt_upgr
                     'fraction' => 0,
                     'timecreated' => 1305830668,
                     'userid' => 4,
-                    'data' => array('answer' => '9.00', '-submit' => 1, '-_try' => 2, '-_rawfraction' => 0),
+                    'data' => array('answer' => '9.00', '-submit' => 1, '-_try' => 1, '-_rawfraction' => 0),
                 ),
                 2 => (object) array(
                     'sequencenumber' => 2,
@@ -433,7 +433,7 @@ class qtype_calculatedsimple_attempt_upgrader_test extends question_attempt_upgr
                     'fraction' => 0.9,
                     'timecreated' => 1305830679,
                     'userid' => 4,
-                    'data' => array('answer' => '15.40', '-submit' => 1, '-_try' => 3, '-_rawfraction' => 1),
+                    'data' => array('answer' => '15.40', '-submit' => 1, '-_try' => 2, '-_rawfraction' => 1),
                 ),
                 3 => (object) array(
                     'sequencenumber' => 3,
@@ -441,7 +441,7 @@ class qtype_calculatedsimple_attempt_upgrader_test extends question_attempt_upgr
                     'fraction' => 0.9,
                     'timecreated' => 1305830679,
                     'userid' => 4,
-                    'data' => array('answer' => '15.40', '-finish' => 1, '-_try' => 3, '-_rawfraction' => 1),
+                    'data' => array('answer' => '15.40', '-finish' => 1, '-_try' => 2, '-_rawfraction' => 1),
                 ),
             ),
         );
@@ -618,7 +618,7 @@ class qtype_calculatedsimple_attempt_upgrader_test extends question_attempt_upgr
                     'fraction' => null,
                     'timecreated' => 1305830744,
                     'userid' => 3,
-                    'data' => array('-_try' => 1, '_separators' => '.$,',
+                    'data' => array('_separators' => '.$,',
                             '_var_a' => '6.1', '_var_b' => '7'),
                 ),
                 1 => (object) array(
index 2b38422..2d5db91 100644 (file)
@@ -216,7 +216,7 @@ class qtype_multianswer_attempt_upgrader_test extends question_attempt_upgrader_
                     'fraction' => null,
                     'timecreated' => 1306425691,
                     'userid' => 4,
-                    'data' => array('-_try' => 1),
+                    'data' => array(),
                 ),
                 1 => (object) array(
                     'sequencenumber' => 1,
@@ -408,7 +408,7 @@ class qtype_multianswer_attempt_upgrader_test extends question_attempt_upgrader_
                     'fraction' => null,
                     'timecreated' => 1306425757,
                     'userid' => 4,
-                    'data' => array('-_try' => '1'),
+                    'data' => array(),
                 ),
                 1 => (object) array(
                     'sequencenumber' => 1,
@@ -615,7 +615,7 @@ class qtype_multianswer_attempt_upgrader_test extends question_attempt_upgrader_
                     'fraction' => null,
                     'timecreated' => 1306425784,
                     'userid' => 3,
-                    'data' => array('-_try' => '1'),
+                    'data' => array(),
                 ),
                 1 => (object) array(
                     'sequencenumber' => 1,
@@ -631,7 +631,7 @@ class qtype_multianswer_attempt_upgrader_test extends question_attempt_upgrader_
                     'fraction' => 1,
                     'timecreated' => 1306425917,
                     'userid' => 3,
-                    'data' => array('sub1_answer' => 'frog', '-_try' => 2,
+                    'data' => array('sub1_answer' => 'frog', '-_try' => 1,
                             '-_rawfraction' => 1.0, '-submit' => 1),
                 ),
                 3 => (object) array(
@@ -640,7 +640,7 @@ class qtype_multianswer_attempt_upgrader_test extends question_attempt_upgrader_
                     'fraction' => 1,
                     'timecreated' => 1306425917,
                     'userid' => 3,
-                    'data' => array('sub1_answer' => 'frog', '-_try' => 2,
+                    'data' => array('sub1_answer' => 'frog', '-_try' => 1,
                             '-_rawfraction' => 1.0, '-finish' => 1),
                 ),
             ),
@@ -1300,7 +1300,7 @@ b) What grade would you give it? _____',
                     'fraction' => null,
                     'timecreated' => 1306425691,
                     'userid' => 4,
-                    'data' => array('-_try' => '1', '_sub1_order' => '29,30,31,32',
+                    'data' => array('_sub1_order' => '29,30,31,32',
                             '_sub3_separators' => '.$,', '_sub4_order' => '38,39,40,41',
                             '_sub5_order' => '42,43,44,45', '_sub7_order' => '49,50',
                             '_sub8_separators' => '.$,'),
@@ -1314,7 +1314,7 @@ b) What grade would you give it? _____',
                     'data' => array('sub1_answer' => '2', 'sub2_answer' => 'dsf',
                             'sub3_answer' => 'sadf', 'sub4_answer' => '1',
                             'sub5_answer' => '2', 'sub6_answer' => 'MOODLE',
-                            'sub7_answer' => 'sadf', 'sub8_answer' => '100%', '-_try' => '2',
+                            'sub7_answer' => 'sadf', 'sub8_answer' => '100%', '-_try' => '1',
                             '-_rawfraction' => '0.38461538461538466', '-submit' => '1'),
                 ),
                 2 => (object) array(
@@ -1326,7 +1326,7 @@ b) What grade would you give it? _____',
                     'data' => array('sub1_answer' => '2', 'sub2_answer' => 'dsf',
                             'sub3_answer' => 'sadf', 'sub4_answer' => '1',
                             'sub5_answer' => '2', 'sub6_answer' => 'MOODLE',
-                            'sub7_answer' => 'sadf', 'sub8_answer' => '100%', '-_try' => '2',
+                            'sub7_answer' => 'sadf', 'sub8_answer' => '100%', '-_try' => '1',
                             '-_rawfraction' => '0.38461538461538466', '-finish' => '1'),
                 ),
             ),
@@ -1974,7 +1974,7 @@ b) What grade would you give it? _____',
                     'fraction' => null,
                     'timecreated' => 1306425757,
                     'userid' => 4,
-                    'data' => array('-_try' => '1', '_sub1_order' => '29,30,31,32',
+                    'data' => array('_sub1_order' => '29,30,31,32',
                             '_sub3_separators' => '.$,', '_sub4_order' => '38,39,40,41',
                             '_sub5_order' => '42,43,44,45', '_sub7_order' => '49,50',
                             '_sub8_separators' => '.$,'),
@@ -2668,7 +2668,7 @@ b) What grade would you give it? _____',
                     'fraction' => null,
                     'timecreated' => 1306425784,
                     'userid' => 3,
-                    'data' => array('-_try' => '1', '_sub1_order' => '29,30,31,32',
+                    'data' => array('_sub1_order' => '29,30,31,32',
                             '_sub3_separators' => '.$,', '_sub4_order' => '38,39,40,41',
                             '_sub5_order' => '42,43,44,45', '_sub7_order' => '49,50',
                             '_sub8_separators' => '.$,'),
@@ -2682,7 +2682,7 @@ b) What grade would you give it? _____',
                     'data' => array('sub1_answer' => '3', 'sub2_answer' => 'asdgf',
                             'sub3_answer' => 'saedf', 'sub4_answer' => '1',
                             'sub5_answer' => '1', 'sub6_answer' => 'sadf',
-                            '-_try' => '2',
+                            '-_try' => '1',
                             '-_rawfraction' => '0.038461538461538464', '-submit' => '1'),
                 ),
                 2 => (object) array(
@@ -2694,7 +2694,7 @@ b) What grade would you give it? _____',
                     'data' => array('sub1_answer' => '2', 'sub2_answer' => 'asdgf',
                             'sub3_answer' => '28.3', 'sub4_answer' => '2',
                             'sub5_answer' => '2', 'sub6_answer' => 'MOODLE',
-                            'sub7_answer' => '0', 'sub8_answer' => '13', '-_try' => '3',
+                            'sub7_answer' => '0', 'sub8_answer' => '13', '-_try' => '2',
                             '-_rawfraction' => '0.53846153846153845', '-submit' => '1'),
                 ),
                 3 => (object) array(
@@ -2706,7 +2706,7 @@ b) What grade would you give it? _____',
                     'data' => array('sub1_answer' => '2', 'sub2_answer' => 'Correct answer',
                             'sub3_answer' => '23.8', 'sub4_answer' => '2',
                             'sub5_answer' => '2', 'sub6_answer' => 'MOODLE',
-                            'sub7_answer' => '0', 'sub8_answer' => '3', '-_try' => '4',
+                            'sub7_answer' => '0', 'sub8_answer' => '3', '-_try' => '3',
                             '-_rawfraction' => '0.92307692307692311', '-submit' => '1'),
                 ),
                 4 => (object) array(
@@ -2718,7 +2718,7 @@ b) What grade would you give it? _____',
                     'data' => array('sub1_answer' => '2', 'sub2_answer' => 'Correct answer',
                             'sub3_answer' => '23.8', 'sub4_answer' => '2',
                             'sub5_answer' => '2', 'sub6_answer' => 'MOODLE',
-                            'sub7_answer' => '0', 'sub8_answer' => '3', '-_try' => '4',
+                            'sub7_answer' => '0', 'sub8_answer' => '3', '-_try' => '3',
                             '-_rawfraction' => '0.92307692307692311', '-finish' => '1'),
                 ),
             ),
index 03d8b38..36e1c08 100644 (file)
@@ -168,6 +168,8 @@ class qtype_multianswer_textfield_renderer extends qtype_multianswer_subq_render
         $response = $qa->get_last_qt_var($fieldname);
         if ($subq->qtype->name() == 'shortanswer') {
             $matchinganswer = $subq->get_matching_answer(array('answer' => $response));
+        } else if ($subq->qtype->name() == 'numerical') {
+            $matchinganswer = $subq->get_matching_answer($response, 1);
         } else {
             $matchinganswer = $subq->get_matching_answer($response);
         }
index 72cf994..d57e157 100644 (file)
@@ -26,6 +26,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+require_once($CFG->dirroot . '/question/type/edit_question_form.php');
 require_once($CFG->dirroot . '/question/type/numerical/questiontype.php');
 
 
@@ -36,6 +37,7 @@ require_once($CFG->dirroot . '/question/type/numerical/questiontype.php');
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 class qtype_numerical_edit_form extends question_edit_form {
+    protected $ap = null;
 
     protected function definition_inner($mform) {
         $this->add_per_answer_fields($mform, get_string('answerno', 'qtype_numerical', '{no}'),
@@ -54,6 +56,7 @@ class qtype_numerical_edit_form extends question_edit_form {
         $tolerance = $mform->createElement('text', 'tolerance',
                 get_string('acceptederror', 'qtype_numerical'));
         $repeatedoptions['tolerance']['type'] = PARAM_NUMBER;
+        $repeatedoptions['tolerance']['default'] = 0;
         array_splice($repeated, 3, 0, array($tolerance));
         $repeated[1]->setSize(10);
 
@@ -98,7 +101,8 @@ class qtype_numerical_edit_form extends question_edit_form {
 
         $unitinputoptions = array(
             qtype_numerical::UNITINPUT => get_string('editableunittext', 'qtype_numerical'),
-            qtype_numerical::UNITSELECT => get_string('unitchoice', 'qtype_numerical'),
+            qtype_numerical::UNITRADIO => get_string('unitchoice', 'qtype_numerical'),
+            qtype_numerical::UNITSELECT => get_string('unitselect', 'qtype_numerical'),
         );
         $mform->addElement('select', 'multichoicedisplay',
                 get_string('studentunitanswer', 'qtype_numerical'), $unitinputoptions);
@@ -255,7 +259,7 @@ class qtype_numerical_edit_form extends question_edit_form {
             if ($trimmedanswer != '') {
                 $answercount++;
                 if (!$this->is_valid_answer($trimmedanswer, $data)) {
-                    $errors['answer[' . $key . ']'] = $this->valid_answer_message();
+                    $errors['answer[' . $key . ']'] = $this->valid_answer_message($trimmedanswer);
                 }
                 if ($data['fraction'][$key] == 1) {
                     $maxgrade = true;
@@ -266,7 +270,7 @@ class qtype_numerical_edit_form extends question_edit_form {
                 }
             } else if ($data['fraction'][$key] != 0 ||
                     !html_is_blank($data['feedback'][$key]['text'])) {
-                $errors['answer[' . $key . ']'] = $this->valid_answer_message();
+                $errors['answer[' . $key . ']'] = $this->valid_answer_message($trimmedanswer);
                 $answercount++;
             }
         }
@@ -276,6 +280,8 @@ class qtype_numerical_edit_form extends question_edit_form {
         if ($maxgrade == false) {
             $errors['fraction[0]'] = get_string('fractionsnomax', 'question');
         }
+
+        return $errors;
     }
 
     /**
@@ -285,7 +291,22 @@ class qtype_numerical_edit_form extends question_edit_form {
      * @return bool whether this is a valid answer.
      */
     protected function is_valid_answer($answer, $data) {
-        return $answer == '*' || is_numeric($answer);
+        return $answer == '*' || $this->is_valid_number($x);
+    }
+
+    /**
+     * Validate that a string is a nubmer formatted correctly for the current locale.
+     * @param string $x a string
+     * @return bool whether $x is a number that the numerical question type can interpret.
+     */
+    protected function is_valid_number($x) {
+        if (is_null($this->ap)) {
+            $this->ap = new qtype_numerical_answer_processor(array());
+        }
+
+        list($value, $unit) = $this->ap->apply_units($x);
+
+        return !is_null($value) && !$unit;
     }
 
     /**
index 94426bc..a2c42c3 100644 (file)
@@ -27,7 +27,7 @@ $string['acceptederror'] = 'Accepted error';
 $string['addingnumerical'] = 'Adding a Numerical question';
 $string['addmoreanswerblanks'] = 'Blanks for {no} More Answers';
 $string['addmoreunitblanks'] = 'Blanks for {no} More Units';
-$string['answermustbenumberorstar'] = 'The answer must be a number, or \'*\'.';
+$string['answermustbenumberorstar'] = 'The answer must be a number, for example -1.234 or 3e8, or \'*\'.';
 $string['answerno'] = 'Answer {$a}';
 $string['decfractionofquestiongrade'] = 'as a fraction (0-1) of the question grade';
 $string['decfractionofresponsegrade'] = 'as a fraction (0-1) of the response grade';
@@ -64,6