Merge branch 'MDL-37476-stable23' of git://github.com/mouneyrac/moodle into MOODLE_23...
authorSam Hemelryk <sam@moodle.com>
Tue, 29 Jan 2013 02:23:35 +0000 (15:23 +1300)
committerSam Hemelryk <sam@moodle.com>
Tue, 29 Jan 2013 02:23:35 +0000 (15:23 +1300)
78 files changed:
admin/user.php
admin/webservice/forms.php
blocks/completionstatus/block_completionstatus.php
blocks/rss_client/editfeed.php
blocks/rss_client/managefeeds.php
blocks/rss_client/viewfeed.php
blocks/selfcompletion/block_selfcompletion.php
course/category.php
course/edit.php
course/editcategory.php
course/index.php
course/lib.php
course/modedit.php
course/rest.php
course/togglecompletion.php
course/yui/dragdrop/dragdrop.js
course/yui/toolboxes/toolboxes.js
enrol/locallib.php
enrol/yui/rolemanager/rolemanager.js
files/renderer.php
grade/report/grader/lib.php
grade/report/grader/styles.css
group/lib.php
install/lang/he_kids/langconfig.php [new file with mode: 0644]
install/lang/tg/langconfig.php [new file with mode: 0644]
lang/en/completion.php
lang/en/question.php
lib/adminlib.php
lib/completionlib.php
lib/db/log.php
lib/form/filemanager.js
lib/javascript-static.js
lib/navigationlib.php
lib/phpunit/bootstrap.php
lib/tests/weblib_test.php
lib/weblib.php
lib/yui/chooserdialogue/chooserdialogue.js
login/index.php
login/index_form.html
message/index.php
message/lib.php
mod/assign/feedback/comments/locallib.php
mod/assign/feedback/file/locallib.php
mod/assign/lib.php
mod/assign/submission/comments/lib.php
mod/assign/submission/comments/locallib.php
mod/assign/submission/file/locallib.php
mod/assign/submission/onlinetext/locallib.php
mod/assign/upgradelib.php
mod/feedback/lib.php
mod/forum/backup/moodle2/restore_forum_activity_task.class.php
mod/forum/lib.php
mod/lesson/format.php
mod/lesson/locallib.php
mod/lesson/pagetypes/essay.php
mod/lesson/pagetypes/matching.php
mod/quiz/cronlib.php
mod/quiz/edit.php
mod/quiz/locallib.php
mod/quiz/styles.css
mod/scorm/locallib.php
mod/scorm/player.php
phpunit.xml.dist
question/format.php
question/format/blackboard_six/formatqti.php
question/format/examview/format.php
question/format/learnwise/format.php
question/format/missingword/format.php
question/format/missingword/lang/en/qformat_missingword.php
question/format/missingword/tests/fixtures/question.missingword1.txt [new file with mode: 0644]
question/format/missingword/tests/fixtures/question.missingword2.txt [new file with mode: 0644]
question/format/missingword/tests/fixtures/question.missingword3.txt [new file with mode: 0644]
question/format/xhtml/format.php
question/type/essay/questiontype.php
report/outline/index.php
user/profile/lib.php
version.php
webservice/rest/locallib.php

index 56e457e..e78e0cd 100644 (file)
         $$column = "<a href=\"user.php?sort=$column&amp;dir=$columndir\">".$string[$column]."</a>$columnicon";
     }
 
-    if ($sort == "name") {
-        $sort = "firstname";
+    $override = new stdClass();
+    $override->firstname = 'firstname';
+    $override->lastname = 'lastname';
+    $fullnamelanguage = get_string('fullnamedisplay', '', $override);
+    if (($CFG->fullnamedisplay == 'firstname lastname') or
+        ($CFG->fullnamedisplay == 'firstname') or
+        ($CFG->fullnamedisplay == 'language' and $fullnamelanguage == 'firstname lastname' )) {
+        $fullnamedisplay = "$firstname / $lastname";
+        if ($sort == "name") { // If sort has already been set to something else then ignore.
+            $sort = "firstname";
+        }
+    } else { // ($CFG->fullnamedisplay == 'language' and $fullnamelanguage == 'lastname firstname').
+        $fullnamedisplay = "$lastname / $firstname";
+        if ($sort == "name") { // This should give the desired sorting based on fullnamedisplay.
+            $sort = "lastname";
+        }
     }
 
     list($extrasql, $params) = $ufiltering->get_sql_filter();
             $users = $nusers;
         }
 
-        $override = new stdClass();
-        $override->firstname = 'firstname';
-        $override->lastname = 'lastname';
-        $fullnamelanguage = get_string('fullnamedisplay', '', $override);
-        if (($CFG->fullnamedisplay == 'firstname lastname') or
-            ($CFG->fullnamedisplay == 'firstname') or
-            ($CFG->fullnamedisplay == 'language' and $fullnamelanguage == 'firstname lastname' )) {
-            $fullnamedisplay = "$firstname / $lastname";
-        } else { // ($CFG->fullnamedisplay == 'language' and $fullnamelanguage == 'lastname firstname')
-            $fullnamedisplay = "$lastname / $firstname";
-        }
-
         $table = new html_table();
         $table->head = array ();
         $table->align = array();
index 13e1c3d..14b8576 100644 (file)
@@ -163,6 +163,7 @@ class external_service_functions_form extends moodleform {
 
         $mform->addElement('searchableselector', 'fids', get_string('name'),
                 $functions, array('multiple'));
+        $mform->addRule('fids', get_string('required'), 'required', null, 'client');
 
         $mform->addElement('hidden', 'id');
         $mform->setType('id', PARAM_INT);
index 5caf743..a7c4115 100644 (file)
@@ -217,7 +217,7 @@ class block_completionstatus extends block_base {
             $this->content->footer = '<br><a href="'.$details->out().'">'.get_string('moredetails', 'completion').'</a>';
         } else {
             // If user is not enrolled, show error
-            $this->content->text = get_string('notenroled', 'completion');
+            $this->content->text = get_string('nottracked', 'completion');
         }
 
         if (has_capability('report/completion:view', $context)) {
index d25e090..30cfefb 100644 (file)
@@ -177,7 +177,7 @@ if ($returnurl) {
 $managefeeds = new moodle_url('/blocks/rss_client/managefeeds.php', $urlparams);
 
 $PAGE->set_url('/blocks/rss_client/editfeed.php', $urlparams);
-$PAGE->set_pagelayout('base');
+$PAGE->set_pagelayout('standard');
 
 if ($rssid) {
     $isadding = false;
@@ -218,10 +218,9 @@ if ($mform->is_cancelled()) {
     $PAGE->set_title($strtitle);
     $PAGE->set_heading($strtitle);
 
-    $settingsurl = new moodle_url('/admin/settings.php?section=blocksettingrss_client');
     $PAGE->navbar->add(get_string('blocks'));
-    $PAGE->navbar->add(get_string('pluginname', 'block_rss_client'), $settingsurl);
-    $PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'));
+    $PAGE->navbar->add(get_string('pluginname', 'block_rss_client'));
+    $PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'), $managefeeds );
     $PAGE->navbar->add($strtitle);
 
     echo $OUTPUT->header();
index 321aed4..58c19e5 100644 (file)
@@ -83,10 +83,9 @@ $PAGE->set_pagelayout('standard');
 $PAGE->set_title($strmanage);
 $PAGE->set_heading($strmanage);
 
-$settingsurl = new moodle_url('/admin/settings.php?section=blocksettingrss_client');
 $managefeeds = new moodle_url('/blocks/rss_client/managefeeds.php', $urlparams);
 $PAGE->navbar->add(get_string('blocks'));
-$PAGE->navbar->add(get_string('pluginname', 'block_rss_client'), $settingsurl);
+$PAGE->navbar->add(get_string('pluginname', 'block_rss_client'));
 $PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'), $managefeeds);
 echo $OUTPUT->header();
 
index 469e621..87aa1fc 100644 (file)
@@ -71,11 +71,10 @@ $strviewfeed = get_string('viewfeed', 'block_rss_client');
 $PAGE->set_title($strviewfeed);
 $PAGE->set_heading($strviewfeed);
 
-$settingsurl = new moodle_url('/admin/settings.php?section=blocksettingrss_client');
 $managefeeds = new moodle_url('/blocks/rss_client/managefeeds.php', $urlparams);
 $PAGE->navbar->add(get_string('blocks'));
-$PAGE->navbar->add(get_string('pluginname', 'block_rss_client'), $settingsurl);
-$PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'));
+$PAGE->navbar->add(get_string('pluginname', 'block_rss_client'));
+$PAGE->navbar->add(get_string('managefeeds', 'block_rss_client'), $managefeeds);
 $PAGE->navbar->add($strviewfeed);
 echo $OUTPUT->header();
 
index 9fe4a84..ae05fe7 100644 (file)
@@ -83,7 +83,7 @@ class block_selfcompletion extends block_base {
 
         // Check this user is enroled
         if (!$info->is_tracked_user($USER->id)) {
-            $this->content->text = get_string('notenroled', 'completion');
+            $this->content->text = get_string('nottracked', 'completion');
             return $this->content;
         }
 
index 7751058..6ede36b 100644 (file)
@@ -144,6 +144,7 @@ if ($editingon && $sesskeyprovided) {
             require_capability('moodle/course:visibility', $coursecontext);
             // Set the visibility of the course. we set the old flag when user manually changes visibility of course.
             $DB->update_record('course', array('id' => $course->id, 'visible' => $visible, 'visibleold' => $visible, 'timemodified' => time()));
+            add_to_log($course->id, "course", ($visible ? 'show' : 'hide'), "edit.php?id=$course->id", $course->id);
         }
     }
 
@@ -172,6 +173,7 @@ if ($editingon && $sesskeyprovided) {
             }
             $DB->set_field('course', 'sortorder', $swapcourse->sortorder, array('id' => $movecourse->id));
             $DB->set_field('course', 'sortorder', $movecourse->sortorder, array('id' => $swapcourse->id));
+            add_to_log($movecourse->id, "course", "move", "edit.php?id=$movecourse->id", $movecourse->id);
         }
     }
 
index 60f9cce..3d4c6b4 100644 (file)
@@ -130,16 +130,8 @@ if ($editform->is_cancelled()) {
     }
     rebuild_course_cache($course->id);
 
-    switch ($returnto) {
-        case 'category':
-        case 'topcat': //redirecting to where the new course was created by default.
-            $url = new moodle_url($CFG->wwwroot.'/course/category.php', array('id'=>$categoryid));
-            break;
-        default:
-            $url = new moodle_url($CFG->wwwroot.'/course/view.php', array('id'=>$course->id));
-            break;
-    }
-    redirect($url);
+    // Redirect user to newly created/updated course.
+    redirect(new moodle_url('/course/view.php', array('id' => $course->id)));
 }
 
 
index 0a9dc89..53eb10e 100644 (file)
@@ -102,6 +102,7 @@ if ($mform->is_cancelled()) {
         $newcategory->theme = $data->theme;
     }
 
+    $logaction = 'update';
     if ($id) {
         // Update an existing category.
         $newcategory->id = $category->id;
@@ -119,10 +120,12 @@ if ($mform->is_cancelled()) {
         $category = create_course_category($newcategory);
         $newcategory->id = $category->id;
         $categorycontext = $category->context;
+        $logaction = 'add';
     }
 
     $newcategory = file_postupdate_standard_editor($newcategory, 'description', $editoroptions, $categorycontext, 'coursecat', 'description', 0);
     $DB->update_record('course_categories', $newcategory);
+    add_to_log(SITEID, "category", $logaction, "editcategory.php?id=$newcategory->id", $newcategory->id);
     fix_course_sortorder();
 
     redirect('category.php?id='.$newcategory->id.'&categoryedit=on');
index 2b4e46b..2c71055 100644 (file)
@@ -230,6 +230,7 @@ if ((!empty($moveup) or !empty($movedown)) and confirm_sesskey()) {
     if ($swapcategory and $movecategory) {
         $DB->set_field('course_categories', 'sortorder', $swapcategory->sortorder, array('id'=>$movecategory->id));
         $DB->set_field('course_categories', 'sortorder', $movecategory->sortorder, array('id'=>$swapcategory->id));
+        add_to_log(SITEID, "category", "move", "editcategory.php?id=$movecategory->id", $movecategory->id);
     }
 
     // finally reorder courses
index bbb855e..097d61b 100644 (file)
@@ -60,6 +60,7 @@ function make_log_url($module, $url) {
         case 'lib':
         case 'admin':
         case 'calendar':
+        case 'category':
         case 'mnet course':
             if (strpos($url, '../') === 0) {
                 $url = ltrim($url, '.');
@@ -1951,7 +1952,8 @@ function get_module_metadata($course, $modnames, $sectionreturn = null) {
         // NOTE: this is legacy stuff, module subtypes are very strongly discouraged!!
         $gettypesfunc =  $modname.'_get_types';
         if (function_exists($gettypesfunc)) {
-            if ($types = $gettypesfunc()) {
+            $types = $gettypesfunc();
+            if (is_array($types) && count($types) > 0) {
                 $group = new stdClass();
                 $group->name = $modname;
                 $group->icon = $OUTPUT->pix_icon('icon', '', $modname, array('class' => 'icon'));
@@ -2000,7 +2002,11 @@ function get_module_metadata($course, $modnames, $sectionreturn = null) {
             $module->archetype = plugin_supports('mod', $modname, FEATURE_MOD_ARCHETYPE, MOD_ARCHETYPE_OTHER);
             $modlist[$course->id][$modname] = $module;
         }
-        $return[$modname] = $modlist[$course->id][$modname];
+        if (isset($modlist[$course->id][$modname])) {
+            $return[$modname] = $modlist[$course->id][$modname];
+        } else {
+            debugging("Invalid module metadata configuration for {$modname}");
+        }
     }
 
     return $return;
@@ -2879,6 +2885,13 @@ function set_coursemodule_visible($id, $visible, $prevstateoverrides=false) {
     if (!$cm = $DB->get_record('course_modules', array('id'=>$id))) {
         return false;
     }
+
+    // Create events and propagate visibility to associated grade items if the value has changed.
+    // Only do this if it's changed to avoid accidently overwriting manual showing/hiding of student grades.
+    if ($cm->visible == $visible) {
+        return true;
+    }
+
     if (!$modulename = $DB->get_field('modules', 'name', array('id'=>$cm->module))) {
         return false;
     }
@@ -2892,7 +2905,7 @@ function set_coursemodule_visible($id, $visible, $prevstateoverrides=false) {
         }
     }
 
-    // hide the associated grade items so the teacher doesn't also have to go to the gradebook and hide them there
+    // Hide the associated grade items so the teacher doesn't also have to go to the gradebook and hide them there.
     $grade_items = grade_item::fetch_all(array('itemtype'=>'mod', 'itemmodule'=>$modulename, 'iteminstance'=>$cm->instance, 'courseid'=>$cm->course));
     if ($grade_items) {
         foreach ($grade_items as $grade_item) {
@@ -3149,13 +3162,16 @@ function moveto_module($mod, $section, $beforemod=NULL) {
 
 /// Update module itself if necessary
 
-    if ($mod->section != $section->id) {
-        $mod->section = $section->id;
-        $DB->update_record("course_modules", $mod);
-        // if moving to a hidden section then hide module
-        if (!$section->visible) {
-            set_coursemodule_visible($mod->id, 0);
-        }
+    // If moving to a hidden section then hide module.
+    if (!$section->visible && $mod->visible) {
+        // Set this in the object because it is sent as a response to ajax calls.
+        set_coursemodule_visible($mod->id, 0, true);
+        $mod->visible = 0;
+    }
+    if ($section->visible && !$mod->visible) {
+        set_coursemodule_visible($mod->id, 1, true);
+        // Set this in the object because it is sent as a response to ajax calls.
+        $mod->visible = $mod->visibleold;
     }
 
 /// Add the module into the new section
@@ -3488,6 +3504,7 @@ function category_delete_full($category, $showfeedback=true) {
     // finally delete the category and it's context
     $DB->delete_records('course_categories', array('id'=>$category->id));
     delete_context(CONTEXT_COURSECAT, $category->id);
+    add_to_log(SITEID, "category", "delete", "index.php", "$category->name (ID $category->id)");
 
     events_trigger('course_category_deleted', $category);
 
@@ -3543,6 +3560,7 @@ function category_delete_move($category, $newparentid, $showfeedback=true) {
     // finally delete the category and it's context
     $DB->delete_records('course_categories', array('id'=>$category->id));
     delete_context(CONTEXT_COURSECAT, $category->id);
+    add_to_log(SITEID, "category", "delete", "index.php", "$category->name (ID $category->id)");
 
     events_trigger('course_category_deleted', $category);
 
@@ -3589,6 +3607,7 @@ function move_courses($courseids, $categoryid) {
             }
 
             $DB->update_record('course', $course);
+            add_to_log($course->id, "course", "move", "edit.php?id=$course->id", $course->id);
 
             $context   = get_context_instance(CONTEXT_COURSE, $course->id);
             context_moved($context, $newparent);
@@ -3621,6 +3640,7 @@ function course_category_hide($category) {
             $DB->set_field('course', 'visible', 0, array('category' => $cat->id));
         }
     }
+    add_to_log(SITEID, "category", "hide", "editcategory.php?id=$category->id", $category->id);
 }
 
 /**
@@ -3644,6 +3664,7 @@ function course_category_show($category) {
             $DB->execute("UPDATE {course} SET visible = visibleold WHERE category = ?", array($cat->id));
         }
     }
+    add_to_log(SITEID, "category", "show", "editcategory.php?id=$category->id", $category->id);
 }
 
 /**
@@ -3676,6 +3697,9 @@ function move_category($category, $newparentcat) {
     // now make it last in new category
     $DB->set_field('course_categories', 'sortorder', MAX_COURSES_IN_CATEGORY*MAX_COURSE_CATEGORIES, array('id'=>$category->id));
 
+    // Log action.
+    add_to_log(SITEID, "category", "move", "editcategory.php?id=$category->id", $category->id);
+
     // and fix the sortorders
     fix_course_sortorder();
 
index 7aa8667..00cc318 100644 (file)
@@ -481,6 +481,7 @@ if ($mform->is_cancelled()) {
         // make sure visibility is set correctly (in particular in calendar)
         // note: allow them to set it even without moodle/course:activityvisibility
         set_coursemodule_visible($fromform->coursemodule, $fromform->visible);
+        $DB->set_field('course_modules', 'visibleold', 1, array('id' => $fromform->coursemodule));
 
         if (isset($fromform->cmidnumber)) { //label
             // set cm idnumber - uniqueness is already verified by form validation
index a7b55c9..11b58aa 100644 (file)
@@ -138,6 +138,7 @@ switch($requestmethod) {
                         }
 
                         moveto_module($cm, $section, $beforemod);
+                        echo json_encode(array('visible' => $cm->visible));
                         break;
                     case 'gettitle':
                         require_capability('moodle/course:manageactivities', $modcontext);
index 19a584b..bae9396 100644 (file)
@@ -45,6 +45,11 @@ if ($courseid) {
     require_login($course);
 
     $completion = new completion_info($course);
+    if (!$completion->is_enabled()) {
+        throw new moodle_exception('completionnotenabled', 'completion');
+    } elseif (!$completion->is_tracked_user($USER->id)) {
+        throw new moodle_exception('nottracked', 'completion');
+    }
 
     // Check if we are marking a user complete via the completion report
     $user = optional_param('user', 0, PARAM_INT);
@@ -136,7 +141,9 @@ if (isguestuser() or !confirm_sesskey()) {
 // Now change state
 $completion = new completion_info($course);
 if (!$completion->is_enabled()) {
-    die;
+    throw new moodle_exception('completionnotenabled', 'completion');
+} elseif (!$completion->is_tracked_user($USER->id)) {
+    throw new moodle_exception('nottracked', 'completion');
 }
 
 // Check completion state is manual
index bd35bd9..e741d9c 100644 (file)
@@ -385,6 +385,9 @@ YUI.add('moodle-course-dragdrop', function(Y) {
                         spinner.show();
                     },
                     success: function(tid, response) {
+                        var responsetext = Y.JSON.parse(response.responseText);
+                        var params = {element: dragnode, visible: responsetext.visible};
+                        M.course.coursebase.invoke_function('set_visibility_resource_ui', params);
                         this.unlock_drag_handle(drag, CSS.EDITINGMOVE);
                         window.setTimeout(function(e) {
                             spinner.hide();
index cec03e0..7304fce 100644 (file)
@@ -557,8 +557,9 @@ YUI.add('moodle-course-toolboxes', function(Y) {
             // Cancel the edit if we lose focus or the escape key is pressed
             thisevent = editor.on('blur', cancel_edittitle);
             listenevents.push(thisevent);
-            thisevent = Y.one('document').on('keyup', function(e) {
-                if (e.keyCode == 27) {
+            thisevent = Y.one('document').on('keydown', function(e) {
+                if (e.keyCode === 27) {
+                    e.preventDefault();
                     cancel_edittitle(e);
                 }
             });
@@ -591,6 +592,26 @@ YUI.add('moodle-course-toolboxes', function(Y) {
                 }
             }, this);
             listenevents.push(thisevent);
+        },
+        /**
+         * Set the visibility of the current resource (identified by the element)
+         * to match the hidden parameter (this is not a toggle).
+         * Only changes the visibility in the browser (no ajax update).
+         * @param args An object with 'element' being the A node containing the resource
+         *             and 'visible' being the state that the visiblity should be set to.
+         * @return void
+         */
+        set_visibility_resource_ui: function(args) {
+            var element = args.element;
+            var shouldbevisible = args.visible;
+            var buttonnode = element.one(CSS.SHOW);
+            var visible = (buttonnode === null);
+            if (visible) {
+                buttonnode = element.one(CSS.HIDE);
+            }
+            if (visible != shouldbevisible) {
+                this.toggle_hide_resource_ui(buttonnode);
+            }
         }
     }, {
         NAME : 'course-resource-toolbox',
index e923c2e..1577265 100644 (file)
@@ -792,7 +792,9 @@ class course_enrolment_manager {
                         break;
                 }
             }
-            $users[$userrole->id]['roles'] = array();
+            if (!isset($users[$userrole->id]['roles'])) {
+                $users[$userrole->id]['roles'] = array();
+            }
             $users[$userrole->id]['roles'][$userrole->roleid] = array(
                 'text' => $roletext,
                 'unchangeable' => !$changeable
index a03bc35..805e894 100644 (file)
@@ -56,7 +56,6 @@ YUI.add('moodle-enrol-rolemanager', function(Y) {
     Y.extend(ROLE, Y.Base, {
         users : [],
         roleAssignmentPanel : null,
-        panelsubmitevent : null,
         rolesLoadedEvent : null,
         escCloseEvent  : null,
         initializer : function(config) {
@@ -75,14 +74,16 @@ YUI.add('moodle-enrol-rolemanager', function(Y) {
             this.rolesLoadedEvent = this.on('assignablerolesloaded', function(){
                 this.rolesLoadedEvent.detach();
                 var panel = this._getRoleAssignmentPanel();
-                this.panelsubmitevent = panel.on('submit', this.addRoleCallback, this);
-                panel.hide().display(user);
+                panel.hide();
+                panel.submitevent = panel.on('submit', this.addRoleCallback, this);
+                panel.display(user);
             }, this);
             this._loadAssignableRoles();
         },
         addRoleCallback : function(e, roleid, userid) {
-            this.panelsubmitevent.detach();
             var panel = this._getRoleAssignmentPanel();
+            panel.submitevent.detach();
+            panel.submitevent = null;
             Y.io(M.cfg.wwwroot+'/enrol/ajax.php', {
                 method:'POST',
                 data:'id='+this.get(COURSEID)+'&action=assign&sesskey='+M.cfg.sesskey+'&roleid='+roleid+'&user='+userid,
@@ -350,6 +351,7 @@ YUI.add('moodle-enrol-rolemanager', function(Y) {
     Y.extend(ROLEPANEL, Y.Base, {
         user : null,
         roles : [],
+        submitevent : null,
         initializer : function() {
             var i, m = this.get(MANIPULATOR);
             var element = Y.Node.create('<div class="enrolpanel roleassign"><div class="container"><div class="header"><h2>'+M.str.role.assignroles+'</h2><div class="close"></div></div><div class="content"></div></div></div>');
@@ -398,6 +400,10 @@ YUI.add('moodle-enrol-rolemanager', function(Y) {
             this.roles = [];
             this.user = null;
             this.get('elementNode').removeClass('visible');
+            if (this.submitevent) {
+                this.submitevent.detach();
+                this.submitevent = null;
+            }
             this.displayed = false;
             return this;
         },
@@ -416,4 +422,4 @@ YUI.add('moodle-enrol-rolemanager', function(Y) {
         }
     }
 
-}, '@VERSION@', {requires:['base','node','io-base','json-parse','test','moodle-enrol-notification']});
\ No newline at end of file
+}, '@VERSION@', {requires:['base','node','io-base','json-parse','test','moodle-enrol-notification']});
index 4c6dc8b..9fc233c 100644 (file)
@@ -304,7 +304,10 @@ class core_files_renderer extends plugin_renderer_base {
     private function fm_js_template_mkdir() {
         $rv = '
 <div class="filemanager fp-mkdir-dlg">
-    <div class="fp-mkdir-dlg-text">'.get_string('newfoldername','repository').'<br/><input type="text" /></div>
+    <div class="fp-mkdir-dlg-text">
+        <label>' . get_string('newfoldername', 'repository') . '</label><br/>
+        <input type="text" />
+    </div>
     <button class="{!}fp-dlg-butcreate">'.get_string('makeafolder').'</button>
     <button class="{!}fp-dlg-butcancel">'.get_string('cancel').'</button>
 </div>';
index 3b4cc42..9f0eabb 100644 (file)
@@ -181,7 +181,7 @@ class grade_report_grader extends grade_report {
         // Were any changes made?
         $changedgrades = false;
 
-        foreach ($data as $varname => $postedvalue) {
+        foreach ($data as $varname => $students) {
 
             $needsupdate = false;
 
@@ -194,113 +194,116 @@ class grade_report_grader extends grade_report {
                 continue;
             }
 
-            $gradeinfo = explode("_", $varname);
-            $userid = clean_param($gradeinfo[1], PARAM_INT);
-            $itemid = clean_param($gradeinfo[2], PARAM_INT);
+            foreach ($students as $userid => $items) {
+                $userid = clean_param($userid, PARAM_INT);
+                foreach ($items as $itemid => $postedvalue) {
+                    $itemid = clean_param($itemid, PARAM_INT);
+
+                    // Was change requested?
+                    $oldvalue = $this->grades[$userid][$itemid];
+                    if ($datatype === 'grade') {
+                        // If there was no grade and there still isn't
+                        if (is_null($oldvalue->finalgrade) && $postedvalue == -1) {
+                            // -1 means no grade
+                            continue;
+                        }
 
-            // Was change requested?
-            $oldvalue = $this->grades[$userid][$itemid];
-            if ($datatype === 'grade') {
-                // If there was no grade and there still isn't
-                if (is_null($oldvalue->finalgrade) && $postedvalue == -1) {
-                    // -1 means no grade
-                    continue;
-                }
+                        // If the grade item uses a custom scale
+                        if (!empty($oldvalue->grade_item->scaleid)) {
 
-                // If the grade item uses a custom scale
-                if (!empty($oldvalue->grade_item->scaleid)) {
+                            if ((int)$oldvalue->finalgrade === (int)$postedvalue) {
+                                continue;
+                            }
+                        } else {
+                            // The grade item uses a numeric scale
 
-                    if ((int)$oldvalue->finalgrade === (int)$postedvalue) {
-                        continue;
-                    }
-                } else {
-                    // The grade item uses a numeric scale
+                            // Format the finalgrade from the DB so that it matches the grade from the client
+                            if ($postedvalue === format_float($oldvalue->finalgrade, $oldvalue->grade_item->get_decimals())) {
+                                continue;
+                            }
+                        }
 
-                    // Format the finalgrade from the DB so that it matches the grade from the client
-                    if ($postedvalue === format_float($oldvalue->finalgrade, $oldvalue->grade_item->get_decimals())) {
-                        continue;
+                        $changedgrades = true;
+
+                    } else if ($datatype === 'feedback') {
+                        if (($oldvalue->feedback === $postedvalue) or ($oldvalue->feedback === NULL and empty($postedvalue))) {
+                            continue;
+                        }
                     }
-                }
 
-                $changedgrades = true;
+                    if (!$gradeitem = grade_item::fetch(array('id'=>$itemid, 'courseid'=>$this->courseid))) {
+                        print_error('invalidgradeitemid');
+                    }
 
-            } else if ($datatype === 'feedback') {
-                if (($oldvalue->feedback === $postedvalue) or ($oldvalue->feedback === NULL and empty($postedvalue))) {
-                    continue;
-                }
-            }
+                    // Pre-process grade
+                    if ($datatype == 'grade') {
+                        $feedback = false;
+                        $feedbackformat = false;
+                        if ($gradeitem->gradetype == GRADE_TYPE_SCALE) {
+                            if ($postedvalue == -1) { // -1 means no grade
+                                $finalgrade = null;
+                            } else {
+                                $finalgrade = $postedvalue;
+                            }
+                        } else {
+                            $finalgrade = unformat_float($postedvalue);
+                        }
 
-            if (!$gradeitem = grade_item::fetch(array('id'=>$itemid, 'courseid'=>$this->courseid))) { // we must verify course id here!
-                print_error('invalidgradeitemid');
-            }
+                        $errorstr = '';
+                        // Warn if the grade is out of bounds.
+                        if (is_null($finalgrade)) {
+                            // ok
+                        } else {
+                            $bounded = $gradeitem->bounded_grade($finalgrade);
+                            if ($bounded > $finalgrade) {
+                            $errorstr = 'lessthanmin';
+                            } else if ($bounded < $finalgrade) {
+                                $errorstr = 'morethanmax';
+                            }
+                        }
+                        if ($errorstr) {
+                            $user = $DB->get_record('user', array('id' => $userid), 'id, firstname, lastname');
+                            $gradestr = new stdClass();
+                            $gradestr->username = fullname($user);
+                            $gradestr->itemname = $gradeitem->get_name();
+                            $warnings[] = get_string($errorstr, 'grades', $gradestr);
+                        }
 
-            // Pre-process grade
-            if ($datatype == 'grade') {
-                $feedback = false;
-                $feedbackformat = false;
-                if ($gradeitem->gradetype == GRADE_TYPE_SCALE) {
-                    if ($postedvalue == -1) { // -1 means no grade
-                        $finalgrade = null;
-                    } else {
-                        $finalgrade = $postedvalue;
+                    } else if ($datatype == 'feedback') {
+                        $finalgrade = false;
+                        $trimmed = trim($postedvalue);
+                        if (empty($trimmed)) {
+                             $feedback = NULL;
+                        } else {
+                             $feedback = $postedvalue;
+                        }
                     }
-                } else {
-                    $finalgrade = unformat_float($postedvalue);
-                }
 
-                $errorstr = '';
-                // Warn if the grade is out of bounds.
-                if (is_null($finalgrade)) {
-                    // ok
-                } else {
-                    $bounded = $gradeitem->bounded_grade($finalgrade);
-                    if ($bounded > $finalgrade) {
-                    $errorstr = 'lessthanmin';
-                    } else if ($bounded < $finalgrade) {
-                        $errorstr = 'morethanmax';
+                    // group access control
+                    if ($separategroups) {
+                        // note: we can not use $this->currentgroup because it would fail badly
+                        //       when having two browser windows each with different group
+                        $sharinggroup = false;
+                        foreach($mygroups as $groupid) {
+                            if (groups_is_member($groupid, $userid)) {
+                                $sharinggroup = true;
+                                break;
+                            }
+                        }
+                        if (!$sharinggroup) {
+                            // either group membership changed or somebody is hacking grades of other group
+                            $warnings[] = get_string('errorsavegrade', 'grades');
+                            continue;
+                        }
                     }
-                }
-                if ($errorstr) {
-                    $user = $DB->get_record('user', array('id' => $userid), 'id, firstname, lastname');
-                    $gradestr = new stdClass();
-                    $gradestr->username = fullname($user);
-                    $gradestr->itemname = $gradeitem->get_name();
-                    $warnings[] = get_string($errorstr, 'grades', $gradestr);
-                }
 
-            } else if ($datatype == 'feedback') {
-                $finalgrade = false;
-                $trimmed = trim($postedvalue);
-                if (empty($trimmed)) {
-                     $feedback = NULL;
-                } else {
-                     $feedback = $postedvalue;
-                }
-            }
+                    $gradeitem->update_final_grade($userid, $finalgrade, 'gradebook', $feedback, FORMAT_MOODLE);
 
-            // group access control
-            if ($separategroups) {
-                // note: we can not use $this->currentgroup because it would fail badly
-                //       when having two browser windows each with different group
-                $sharinggroup = false;
-                foreach($mygroups as $groupid) {
-                    if (groups_is_member($groupid, $userid)) {
-                        $sharinggroup = true;
-                        break;
+                    // We can update feedback without reloading the grade item as it doesn't affect grade calculations
+                    if ($datatype === 'feedback') {
+                        $this->grades[$userid][$itemid]->feedback = $feedback;
                     }
                 }
-                if (!$sharinggroup) {
-                    // either group membership changed or somebody is hacking grades of other group
-                    $warnings[] = get_string('errorsavegrade', 'grades');
-                    continue;
-                }
-            }
-
-            $gradeitem->update_final_grade($userid, $finalgrade, 'gradebook', $feedback, FORMAT_MOODLE);
-
-            // We can update feedback without reloading the grade item as it doesn't affect grade calculations
-            if ($datatype === 'feedback') {
-                $this->grades[$userid][$itemid]->feedback = $feedback;
             }
         }
 
@@ -1017,7 +1020,7 @@ class grade_report_grader extends grade_report {
                             }
                             $attributes = array('tabindex' => $tabindices[$item->id]['grade'], 'id'=>'grade_'.$userid.'_'.$item->id);
                             $itemcell->text .= html_writer::label(get_string('typescale', 'grades'), $attributes['id'], false, array('class' => 'accesshide'));
-                            $itemcell->text .= html_writer::select($scaleopt, 'grade_'.$userid.'_'.$item->id, $gradeval, array(-1=>$nogradestr), $attributes);
+                            $itemcell->text .= html_writer::select($scaleopt, 'grade['.$userid.']['.$item->id.']', $gradeval, array(-1=>$nogradestr), $attributes);
                         } elseif(!empty($scale)) {
                             $scales = explode(",", $scale->scale);
 
@@ -1036,8 +1039,8 @@ class grade_report_grader extends grade_report {
                         if ($this->get_pref('quickgrading') and $grade->is_editable()) {
                             $value = format_float($gradeval, $decimalpoints);
                             $itemcell->text .= '<input size="6" tabindex="' . $tabindices[$item->id]['grade']
-                                          . '" type="text" class="text" title="'. $strgrade .'" name="grade_'
-                                          .$userid.'_' .$item->id.'" id="grade_'.$userid.'_'.$item->id.'" value="'.$value.'" />';
+                                          . '" type="text" class="text" title="'. $strgrade .'" name="grade['
+                                          .$userid.'][' .$item->id.']" id="grade_'.$userid.'_'.$item->id.'" value="'.$value.'" />';
                         } else {
                             $itemcell->text .= html_writer::tag('span', format_float($gradeval, $decimalpoints), array('class'=>"gradevalue$hidden$gradepass"));
                         }
@@ -1048,7 +1051,7 @@ class grade_report_grader extends grade_report {
                     if ($this->get_pref('showquickfeedback') and $grade->is_editable()) {
 
                         $itemcell->text .= '<input class="quickfeedback" tabindex="' . $tabindices[$item->id]['feedback'].'" id="feedback_'.$userid.'_'.$item->id
-                                      . '" size="6" title="' . $strfeedback . '" type="text" name="feedback_'.$userid.'_'.$item->id.'" value="' . s($grade->feedback) . '" />';
+                                      . '" size="6" title="' . $strfeedback . '" type="text" name="feedback['.$userid.']['.$item->id.']" value="' . s($grade->feedback) . '" />';
                     }
 
                 } else { // Not editing
@@ -1730,25 +1733,21 @@ class grade_report_grader extends grade_report {
             // Will this number of students result in more fields that we are allowed?
             $maxinputvars = ini_get('max_input_vars');
             if ($maxinputvars !== false) {
-                $fieldspergradeitem = 0; // The number of fields output per grade item for each student
+                // We can't do anything about there being more grade items than max_input_vars,
+                // but we can decrease number of students per page if there are >= max_input_vars
+                $fieldsperstudent = 0; // The number of fields output per student
 
-                if ($this->get_pref('quickgrading')) {
-                    // One grade field
-                    $fieldspergradeitem ++;
-                }
-                if ($this->get_pref('showquickfeedback')) {
-                    // One feedback field
-                    $fieldspergradeitem ++;
+                if ($this->get_pref('quickgrading') || $this->get_pref('showquickfeedback')) {
+                    // Each array (grade, feedback) will gain one element
+                    $fieldsperstudent ++;
                 }
 
-                $fieldsperstudent = $fieldspergradeitem * count($this->gtree->get_items());
                 $fieldsrequired = $studentsperpage * $fieldsperstudent;
-                if ($fieldsrequired > $maxinputvars) {
-                    $studentsperpage = floor($maxinputvars / $fieldsperstudent);
+                if ($fieldsrequired >= $maxinputvars) {
+                    $studentsperpage = $maxinputvars - 1; // Subtract one to be on the safe side
                     if ($studentsperpage<1) {
-                        // Make sure students per page doesn't fall below 1
-                        // PHP max_input_vars could potentially be reached with 1 student
-                        // if there are >500 grade items and quickgrading and showquickfeedback are on
+                        // Make sure students per page doesn't fall below 1, though if your
+                        // max_input_vars is only 1 you've got bigger problems!
                         $studentsperpage = 1;
                     }
 
index 2babb4e..3652d71 100644 (file)
@@ -578,7 +578,7 @@ background-color:#f3ead8;
     vertical-align:middle;
 }
 
-.path-grade-report-grader .yui-overlay {
+.path-grade-report-grader .yui3-overlay {
     background-color: #FFEE69;
     border-color: #D4C237 #A6982B #A6982B;
     border-style: solid;
@@ -588,15 +588,15 @@ background-color:#f3ead8;
     font-size: 0.7em;
 }
 
-.path-grade-report-grader .yui-overlay .fullname {
+.path-grade-report-grader .yui3-overlay .fullname {
     color: #5F3E00;
     font-weight: bold;
 }
-.path-grade-report-grader .yui-overlay .itemname {
+.path-grade-report-grader .yui3-overlay .itemname {
     color: #194F3E;
     font-weight: bold;
 }
-.path-grade-report-grader .yui-overlay .feedback {
+.path-grade-report-grader .yui3-overlay .feedback {
     color: #5F595E;
 }
 /* table#user-grades td */
@@ -605,7 +605,7 @@ background-color:#f3ead8;
   text-align: left;
 }
 
-.path-grade-report-grader .yui-overlay a.container-close {
+.path-grade-report-grader .yui3-overlay a.container-close {
   margin-top: -3px;
 }
 
index c9e2cc0..684ed47 100644 (file)
@@ -772,7 +772,7 @@ function groups_calculate_role_people($rs, $context) {
                 $roles[$roledata->id] = $roledata;
             }
             // Record that user has role
-            $users[$rec->userid]->roles[] = $roles[$rec->roleid];
+            $users[$rec->userid]->roles[$rec->roleid] = $roles[$rec->roleid];
         }
     }
     $rs->close();
@@ -802,7 +802,8 @@ function groups_calculate_role_people($rs, $context) {
         } else if($rolecount > 1) {
             $roleid = '*';
         } else {
-            $roleid = $userdata->roles[0]->id;
+            $userrole = reset($userdata->roles);
+            $roleid = $userrole->id;
         }
         $roles[$roleid]->users[$userid] = $userdata;
     }
diff --git a/install/lang/he_kids/langconfig.php b/install/lang/he_kids/langconfig.php
new file mode 100644 (file)
index 0000000..760ef79
--- /dev/null
@@ -0,0 +1,34 @@
+<?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/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['parentlanguage'] = 'he';
+$string['thislanguage'] = 'Hebrew kids';
diff --git a/install/lang/tg/langconfig.php b/install/lang/tg/langconfig.php
new file mode 100644 (file)
index 0000000..8340cfd
--- /dev/null
@@ -0,0 +1,33 @@
+<?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/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['thislanguage'] = 'тоҷикӣ';
index f7e0829..3bb91d1 100644 (file)
@@ -135,9 +135,10 @@ $string['markcomplete']='Mark complete';
 $string['markedcompleteby']='Marked complete by {$a}';
 $string['markingyourselfcomplete']='Marking yourself complete';
 $string['moredetails']='More details';
-$string['notcompleted'] = 'Not completed';
 $string['nocriteriaset']='No completion criteria set for this course';
+$string['notcompleted'] = 'Not completed';
 $string['notenroled']='You are not enrolled in this course';
+$string['nottracked']='You are currently not being tracked by completion in this course';
 $string['notyetstarted']='Not yet started';
 $string['overallcriteriaaggregation']='Overall criteria type aggregation';
 $string['pending']='Pending';
index 56d1a07..0690186 100644 (file)
@@ -183,13 +183,13 @@ $string['invalidcategoryidforparent'] = 'Invalid category id for parent!';
 $string['invalidcategoryidtomove'] = 'Invalid category id to move!';
 $string['invalidconfirm'] = 'Confirmation string was incorrect';
 $string['invalidcontextinhasanyquestions'] = 'Invalid context passed to question_context_has_any_questions.';
+$string['invalidgrade'] = 'Grades ({$a}) do not match grade options - question skipped.';
 $string['invalidpenalty'] = 'Invalid penalty';
 $string['invalidwizardpage'] = 'Incorrect or no wizard page specified!';
 $string['lastmodifiedby'] = 'Last modified by';
 $string['linkedfiledoesntexist'] = 'Linked file {$a} doesn\'t exist';
 $string['makechildof'] = 'Make child of \'{$a}\'';
 $string['maketoplevelitem'] = 'Move to top level';
-$string['matcherror'] = 'Grades do not match grade options - question skipped';
 $string['matchgrades'] = 'Match grades';
 $string['matchgradeserror'] = 'Error if grade not listed';
 $string['matchgradesnearest'] = 'Nearest grade if not listed';
@@ -416,6 +416,7 @@ $string['technicalinfoquestionsummary'] = 'Question summary: {$a}';
 $string['technicalinforightsummary'] = 'Right answer summary: {$a}';
 $string['technicalinfostate'] = 'Question state: {$a}';
 $string['unknownbehaviour'] = 'Unknown behaviour: {$a}.';
+$string['unknownorunhandledtype'] = 'Unknown or unhandled question type: {$a}';
 $string['unknownquestion'] = 'Unknown question: {$a}.';
 $string['unknownquestioncatregory'] = 'Unknown question category: {$a}.';
 $string['unknownquestiontype'] = 'Unknown question type: {$a}.';
index d638e50..18f06e7 100644 (file)
@@ -7679,7 +7679,7 @@ class admin_setting_configcolourpicker extends admin_setting {
         $PAGE->requires->js_init_call('M.util.init_colour_picker', array($this->get_id(), $this->previewconfig));
         $content  = html_writer::start_tag('div', array('class'=>'form-colourpicker defaultsnext'));
         $content .= html_writer::tag('div', $OUTPUT->pix_icon('i/loading', get_string('loading', 'admin'), 'moodle', array('class'=>'loadingicon')), array('class'=>'admin_colourpicker clearfix'));
-        $content .= html_writer::empty_tag('input', array('type'=>'text','id'=>$this->get_id(), 'name'=>$this->get_full_name(), 'value'=>$this->get_setting(), 'size'=>'12'));
+        $content .= html_writer::empty_tag('input', array('type'=>'text','id'=>$this->get_id(), 'name'=>$this->get_full_name(), 'value'=>$data, 'size'=>'12'));
         if (!empty($this->previewconfig)) {
             $content .= html_writer::empty_tag('input', array('type'=>'button','id'=>$this->get_id().'_preview', 'value'=>get_string('preview'), 'class'=>'admin_colourpicker_preview'));
         }
index fcc6f58..b293c5c 100644 (file)
@@ -1021,7 +1021,7 @@ class completion_info {
      * @return bool
      */
     public function is_tracked_user($userid) {
-        return is_enrolled(context_course::instance($this->course->id), $userid, '', true);
+        return is_enrolled(context_course::instance($this->course->id), $userid, 'moodle/course:isincompletionreports', true);
     }
 
     /**
@@ -1038,7 +1038,7 @@ class completion_info {
         global $DB;
 
         list($enrolledsql, $enrolledparams) = get_enrolled_sql(
-                context_course::instance($this->course->id), '', $groupid, true);
+                context_course::instance($this->course->id), 'moodle/course:isincompletionreports', $groupid, true);
         $sql  = 'SELECT COUNT(eu.id) FROM (' . $enrolledsql . ') eu JOIN {user} u ON u.id = eu.id';
         if ($where) {
             $sql .= " WHERE $where";
index 94abc81..8d62b39 100644 (file)
@@ -40,6 +40,9 @@ $logs = array(
     array('module'=>'course', 'action'=>'view', 'mtable'=>'course', 'field'=>'fullname'),
     array('module'=>'course', 'action'=>'view section', 'mtable'=>'course_sections', 'field'=>'name'),
     array('module'=>'course', 'action'=>'update', 'mtable'=>'course', 'field'=>'fullname'),
+    array('module'=>'course', 'action'=>'hide', 'mtable'=>'course', 'field'=>'fullname'),
+    array('module'=>'course', 'action'=>'show', 'mtable'=>'course', 'field'=>'fullname'),
+    array('module'=>'course', 'action'=>'move', 'mtable'=>'course', 'field'=>'fullname'),
     array('module'=>'course', 'action'=>'enrol', 'mtable'=>'course', 'field'=>'fullname'), // there should be some way to store user id of the enrolled user!
     array('module'=>'course', 'action'=>'unenrol', 'mtable'=>'course', 'field'=>'fullname'), // there should be some way to store user id of the enrolled user!
     array('module'=>'course', 'action'=>'report log', 'mtable'=>'course', 'field'=>'fullname'),
@@ -47,6 +50,11 @@ $logs = array(
     array('module'=>'course', 'action'=>'report outline', 'mtable'=>'course', 'field'=>'fullname'),
     array('module'=>'course', 'action'=>'report participation', 'mtable'=>'course', 'field'=>'fullname'),
     array('module'=>'course', 'action'=>'report stats', 'mtable'=>'course', 'field'=>'fullname'),
+    array('module'=>'category', 'action'=>'add', 'mtable'=>'course_categories', 'field'=>'name'),
+    array('module'=>'category', 'action'=>'hide', 'mtable'=>'course_categories', 'field'=>'name'),
+    array('module'=>'category', 'action'=>'move', 'mtable'=>'course_categories', 'field'=>'name'),
+    array('module'=>'category', 'action'=>'show', 'mtable'=>'course_categories', 'field'=>'name'),
+    array('module'=>'category', 'action'=>'update', 'mtable'=>'course_categories', 'field'=>'name'),
     array('module'=>'message', 'action'=>'write', 'mtable'=>'user', 'field'=>$DB->sql_concat('firstname', "' '" , 'lastname')),
     array('module'=>'message', 'action'=>'read', 'mtable'=>'user', 'field'=>$DB->sql_concat('firstname', "' '" , 'lastname')),
     array('module'=>'message', 'action'=>'add contact', 'mtable'=>'user', 'field'=>$DB->sql_concat('firstname', "' '" , 'lastname')),
index 21b4689..9e825e3 100644 (file)
@@ -316,6 +316,7 @@ M.form_filemanager.init = function(Y, options) {
                             on('keydown', function(e){
                                 if (e.keyCode == 13) {Y.bind(perform_action, this)(e);}
                             }, this);
+                        node.one('label').set('for', 'fm-newname-' + this.client_id);
                         node.all('.fp-dlg-butcancel').on('click', function(e){e.preventDefault();this.mkdir_dialog.hide();}, this);
                         node.all('.fp-dlg-curpath').set('id', 'fm-curpath-'+this.client_id);
                     }
index 858fe24..d7fd22e 100644 (file)
@@ -813,6 +813,16 @@ M.util.focus_login_form = function(Y) {
     }
 }
 
+/**
+ * Set focus on login error message
+ */
+M.util.focus_login_error = function(Y) {
+    var errorlog = Y.one('#loginerrormessage');
+
+    if (errorlog) {
+        errorlog.focus();
+    }
+}
 /**
  * Adds lightbox hidden element that covers the whole node.
  *
@@ -1454,7 +1464,7 @@ M.util.help_icon = {
                         });
                         this.overlay.render(Y.one(document.body));
 
-                        footerbtn.on('click', this.overlay.hide, this.overlay);
+                        footerbtn.on('click', this.close, this);
 
                         var boundingBox = this.overlay.get("boundingBox");
 
@@ -1515,8 +1525,14 @@ M.util.help_icon = {
                     },
 
                     display_callback : function(content) {
-                        content = '<div role="alert">' + content + '</div>';
-                        this.overlay.set('bodyContent', content);
+                        var contentnode, heading;
+                        contentnode = Y.Node.create('<div role="alert">' + content + '</div>');
+                        this.overlay.set('bodyContent', contentnode);
+                        heading = contentnode.one('h1');
+                        if (heading) {
+                            heading.set('tabIndex', 0);
+                            heading.focus();
+                        }
                     },
 
                     hideContent : function() {
index d0b2d5f..856c74f 100644 (file)
@@ -2323,8 +2323,8 @@ class global_navigation extends navigation_node {
 
         if (!empty($CFG->messaging)) {
             $messageargs = null;
-            if ($USER->id!=$user->id) {
-                $messageargs = array('id'=>$user->id);
+            if ($USER->id != $user->id) {
+                $messageargs = array('user1' => $user->id);
             }
             $url = new moodle_url('/message/index.php',$messageargs);
             $usernode->add(get_string('messages', 'message'), $url, self::TYPE_SETTING, null, 'messages');
index f94c295..2339cf8 100644 (file)
@@ -93,12 +93,8 @@ $CFG->filepermissions = ($CFG->directorypermissions & 0666);
 if (!isset($CFG->phpunit_dataroot)) {
     phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGERROR, 'Missing $CFG->phpunit_dataroot in config.php, can not run tests!');
 }
-// Ensure we access to phpunit_dataroot realpath always.
-$CFG->phpunit_dataroot = realpath($CFG->phpunit_dataroot);
 
-if (isset($CFG->dataroot) and $CFG->phpunit_dataroot === $CFG->dataroot) {
-    phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGERROR, '$CFG->dataroot and $CFG->phpunit_dataroot must not be identical, can not run tests!');
-}
+// Create test dir if does not exists yet.
 if (!file_exists($CFG->phpunit_dataroot)) {
     mkdir($CFG->phpunit_dataroot, $CFG->directorypermissions);
 }
@@ -106,6 +102,13 @@ if (!is_dir($CFG->phpunit_dataroot)) {
     phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGERROR, '$CFG->phpunit_dataroot directory can not be created, can not run tests!');
 }
 
+// Ensure we access to phpunit_dataroot realpath always.
+$CFG->phpunit_dataroot = realpath($CFG->phpunit_dataroot);
+
+if (isset($CFG->dataroot) and $CFG->phpunit_dataroot === $CFG->dataroot) {
+    phpunit_bootstrap_error(PHPUNIT_EXITCODE_CONFIGERROR, '$CFG->dataroot and $CFG->phpunit_dataroot must not be identical, can not run tests!');
+}
+
 if (!is_writable($CFG->phpunit_dataroot)) {
     // try to fix permissions if possible
     if (function_exists('posix_getuid')) {
index c5a75c8..4ac75de 100644 (file)
@@ -179,8 +179,23 @@ class web_testcase extends advanced_testcase {
     }
 
     function test_out_as_local_url() {
+        global $CFG;
+        // Test http url.
         $url1 = new moodle_url('/lib/tests/weblib_test.php');
         $this->assertEquals('/lib/tests/weblib_test.php', $url1->out_as_local_url());
+
+        // Test https url.
+        $httpswwwroot = str_replace("http://", "https://", $CFG->wwwroot);
+        $url2 = new moodle_url($httpswwwroot.'/login/profile.php');
+        $this->assertEquals('/login/profile.php', $url2->out_as_local_url());
+
+        // Test http url matching wwwroot.
+        $url3 = new moodle_url($CFG->wwwroot);
+        $this->assertEquals('', $url3->out_as_local_url());
+
+        // Test http url matching wwwroot ending with slash (/).
+        $url3 = new moodle_url($CFG->wwwroot.'/');
+        $this->assertEquals('/', $url3->out_as_local_url());
     }
 
     /**
@@ -192,6 +207,31 @@ class web_testcase extends advanced_testcase {
         $url2->out_as_local_url();
     }
 
+    /**
+     * You should get error with modified url
+     *
+     * @expectedException coding_exception
+     * @return void
+     */
+    public function test_modified_url_out_as_local_url_error() {
+        global $CFG;
+
+        $modifiedurl = $CFG->wwwroot.'1';
+        $url3 = new moodle_url($modifiedurl.'/login/profile.php');
+        $url3->out_as_local_url();
+    }
+
+    /**
+     * Try get local url from external https url and you should get error
+     *
+     * @expectedException coding_exception
+     * @return void
+     */
+    public function test_https_out_as_local_url_error() {
+        $url4 = new moodle_url('https://www.google.com/lib/tests/weblib_test.php');
+        $url4->out_as_local_url();
+    }
+
     public function test_clean_text() {
         $text = "lala <applet>xx</applet>";
         $this->assertEquals($text, clean_text($text, FORMAT_PLAIN));
index 500467b..6c8ebab 100644 (file)
@@ -747,12 +747,18 @@ class moodle_url {
         global $CFG;
 
         $url = $this->out($escaped, $overrideparams);
-
-        if (strpos($url, $CFG->wwwroot) !== 0) {
+        $httpswwwroot = str_replace("http://", "https://", $CFG->wwwroot);
+
+        // $url should be equal to wwwroot or httpswwwroot. If not then throw exception.
+        if (($url === $CFG->wwwroot) || (strpos($url, $CFG->wwwroot.'/') === 0)) {
+            $localurl = substr($url, strlen($CFG->wwwroot));
+            return !empty($localurl) ? $localurl : '';
+        } else if (($url === $httpswwwroot) || (strpos($url, $httpswwwroot.'/') === 0)) {
+            $localurl = substr($url, strlen($httpswwwroot));
+            return !empty($localurl) ? $localurl : '';
+        } else {
             throw new coding_exception('out_as_local_url called on a non-local URL');
         }
-
-        return str_replace($CFG->wwwroot, '', $url);
     }
 
     /**
index 03a19cf..8627b5a 100644 (file)
@@ -143,7 +143,7 @@ YUI.add('moodle-core-chooserdialogue', function(Y) {
             this.listenevents.push(thisevent);
 
             // Grab global keyup events and handle them
-            thisevent = Y.one('document').on('keyup', this.handle_key_press, this);
+            thisevent = Y.one('document').on('keydown', this.handle_key_press, this);
             this.listenevents.push(thisevent);
 
             // Add references to various elements we adjust
index 1847544..4526ba6 100644 (file)
@@ -345,7 +345,9 @@ if (isloggedin() and !isguestuser()) {
     echo $OUTPUT->box_end();
 } else {
     include("index_form.html");
-    if (!empty($CFG->loginpageautofocus)) {
+    if ($errormsg) {
+        $PAGE->requires->js_init_call('M.util.focus_login_error', null, true);
+    } else if (!empty($CFG->loginpageautofocus)) {
         //focus username or password
         $PAGE->requires->js_init_call('M.util.focus_login_form', null, true);
     }
index 1765064..f7557a5 100644 (file)
@@ -30,9 +30,10 @@ if (empty($CFG->xmlstrictheaders) and !empty($CFG->loginpasswordautocomplete)) {
         </div>
         <?php
           if (!empty($errormsg)) {
-              echo '<div class="loginerrors">';
+              echo html_writer::start_tag('div', array('class' => 'loginerrors'));
+              echo html_writer::link('#', $errormsg, array('id' => 'loginerrormessage', 'class' => 'accesshide'));
               echo $OUTPUT->error_text($errormsg);
-              echo '</div>';
+              echo html_writer::end_tag('div');
           }
         ?>
         <form action="<?php echo $CFG->httpswwwroot; ?>/login/index.php" method="post" id="login" <?php echo $autocomplete; ?> >
index daaa5ff..cacf6c7 100644 (file)
@@ -64,21 +64,22 @@ $advancedsearch = optional_param('advanced', 0, PARAM_INT);
 //if they have numerous contacts or are viewing course participants we might need to page through them
 $page = optional_param('page', 0, PARAM_INT);
 
-$url = new moodle_url('/message/index.php');
+$url = new moodle_url('/message/index.php', array('user1' => $user1id));
 
 if ($user2id !== 0) {
     $url->param('user2', $user2id);
-}
 
-if ($user2id !== 0) {
     //Switch view back to contacts if:
     //1) theyve searched and selected a user
     //2) they've viewed recent messages or notifications and clicked through to a user
-    if ($viewing == MESSAGE_VIEW_SEARCH || $viewing == MESSAGE_VIEW_SEARCH || $viewing == MESSAGE_VIEW_RECENT_NOTIFICATIONS) {
+    if ($viewing == MESSAGE_VIEW_SEARCH || $viewing == MESSAGE_VIEW_RECENT_NOTIFICATIONS) {
         $viewing = MESSAGE_VIEW_CONTACTS;
     }
 }
-$url->param('viewing', $viewing);
+
+if ($viewing != MESSAGE_VIEW_UNREAD_MESSAGES) {
+    $url->param('viewing', $viewing);
+}
 
 $PAGE->set_url($url);
 
@@ -86,21 +87,24 @@ $PAGE->set_context(get_context_instance(CONTEXT_USER, $USER->id));
 $PAGE->navigation->extend_for_user($USER);
 $PAGE->set_pagelayout('course');
 
+$navigationurl = new moodle_url('/message/index.php', array('user1' => $user1id));
+navigation_node::override_active_url($navigationurl);
+
 // Disable message notification popups while the user is viewing their messages
 $PAGE->set_popup_notification_allowed(false);
 
-$context = get_context_instance(CONTEXT_SYSTEM);
+//$context = get_context_instance(CONTEXT_SYSTEM);
 
 $user1 = null;
 $currentuser = true;
-$showcontactactionlinks = true;
+$showactionlinks = true;
 if ($user1id != $USER->id) {
     $user1 = $DB->get_record('user', array('id' => $user1id));
     if (!$user1) {
         print_error('invaliduserid');
     }
     $currentuser = false;//if we're looking at someone else's messages we need to lock/remove some UI elements
-    $showcontactactionlinks = false;
+    $showactionlinks = false;
 } else {
     $user1 = $USER;
 }
@@ -115,12 +119,18 @@ if (!empty($user2id)) {
 }
 unset($user2id);
 
+$systemcontext = context_system::instance();
+
 // Is the user involved in the conversation?
 // Do they have the ability to read other user's conversations?
-if (!message_current_user_is_involved($user1, $user2) && !has_capability('moodle/site:readallmessages', $context)) {
+if (!message_current_user_is_involved($user1, $user2) && !has_capability('moodle/site:readallmessages', $systemcontext)) {
     print_error('accessdenied','admin');
 }
 
+$PAGE->set_context(context_user::instance($user1->id));
+$PAGE->set_pagelayout('course');
+$PAGE->navigation->extend_for_user($user1);
+
 /// Process any contact maintenance requests there may be
 if ($addcontact and confirm_sesskey()) {
     add_to_log(SITEID, 'message', 'add contact', 'index.php?user1='.$addcontact.'&amp;user2='.$USER->id, $addcontact);
@@ -142,10 +152,10 @@ if ($unblockcontact and confirm_sesskey()) {
 
 //was a message sent? Do NOT allow someone looking at someone else's messages to send them.
 $messageerror = null;
-if ($currentuser && !empty($user2) && has_capability('moodle/site:sendmessage', $context)) {
+if ($currentuser && !empty($user2) && has_capability('moodle/site:sendmessage', $systemcontext)) {
     // Check that the user is not blocking us!!
     if ($contact = $DB->get_record('message_contacts', array('userid' => $user2->id, 'contactid' => $user1->id))) {
-        if ($contact->blocked and !has_capability('moodle/site:readallmessages', $context)) {
+        if ($contact->blocked and !has_capability('moodle/site:readallmessages', $systemcontext)) {
             $messageerror = get_string('userisblockingyou', 'message');
         }
     }
@@ -214,8 +224,10 @@ if (!empty($user2)) {
 }
 $countunreadtotal = message_count_unread_messages($user1);
 
-if ($countunreadtotal == 0 && $viewing == MESSAGE_VIEW_UNREAD_MESSAGES && empty($user2)) {
-    //default to showing the search
+if ($currentuser && $countunreadtotal == 0 && $viewing == MESSAGE_VIEW_UNREAD_MESSAGES && empty($user2)) {
+    // If the user has no unread messages, show the search box.
+    // We don't do this when a user is viewing another user's messages as search doesn't
+    // handle user A searching user B's messages properly.
     $viewing = MESSAGE_VIEW_SEARCH;
 }
 
@@ -224,7 +236,7 @@ $countblocked = count($blockedusers);
 
 list($onlinecontacts, $offlinecontacts, $strangers) = message_get_contacts($user1, $user2);
 
-message_print_contact_selector($countunreadtotal, $viewing, $user1, $user2, $blockedusers, $onlinecontacts, $offlinecontacts, $strangers, $showcontactactionlinks, $page);
+message_print_contact_selector($countunreadtotal, $viewing, $user1, $user2, $blockedusers, $onlinecontacts, $offlinecontacts, $strangers, $showactionlinks, $page);
 
 echo html_writer::start_tag('div', array('class' => 'messagearea mdl-align'));
     if (!empty($user2)) {
@@ -280,11 +292,11 @@ echo html_writer::start_tag('div', array('class' => 'messagearea mdl-align'));
 
             $messagehistorylink .= html_writer::end_tag('div');
 
-            message_print_message_history($user1, $user2, $search, $displaycount, $messagehistorylink, $viewingnewmessages);
+            message_print_message_history($user1, $user2, $search, $displaycount, $messagehistorylink, $viewingnewmessages, $showactionlinks);
         echo html_writer::end_tag('div');
 
         //send message form
-        if ($currentuser && has_capability('moodle/site:sendmessage', $context)) {
+        if ($currentuser && has_capability('moodle/site:sendmessage', $systemcontext)) {
             echo html_writer::start_tag('div', array('class' => 'mdl-align messagesend'));
                 if (!empty($messageerror)) {
                     echo html_writer::tag('span', $messageerror, array('id' => 'messagewarning'));
@@ -313,7 +325,7 @@ echo html_writer::start_tag('div', array('class' => 'messagearea mdl-align'));
     } else if ($viewing == MESSAGE_VIEW_SEARCH) {
         message_print_search($advancedsearch, $user1);
     } else if ($viewing == MESSAGE_VIEW_RECENT_CONVERSATIONS) {
-        message_print_recent_conversations($user1);
+        message_print_recent_conversations($user1, false, $showactionlinks);
     } else if ($viewing == MESSAGE_VIEW_RECENT_NOTIFICATIONS) {
         message_print_recent_notifications($user1);
     }
index 1fc1cd3..0d76548 100644 (file)
@@ -89,11 +89,11 @@ define('MESSAGE_DEFAULT_PERMITTED', 'permitted');
  * @param array $onlinecontacts an array of $user1's online contacts
  * @param array $offlinecontacts an array of $user1's offline contacts
  * @param array $strangers an array of users who have messaged $user1 who aren't contacts
- * @param bool $showcontactactionlinks show action links (add/remove contact etc) next to the users in the contact selector
+ * @param bool $showactionlinks show action links (add/remove contact etc)
  * @param int $page if there are so many users listed that they have to be split into pages what page are we viewing
  * @return void
  */
-function message_print_contact_selector($countunreadtotal, $viewing, $user1, $user2, $blockedusers, $onlinecontacts, $offlinecontacts, $strangers, $showcontactactionlinks, $page=0) {
+function message_print_contact_selector($countunreadtotal, $viewing, $user1, $user2, $blockedusers, $onlinecontacts, $offlinecontacts, $strangers, $showactionlinks, $page=0) {
     global $PAGE;
 
     echo html_writer::start_tag('div', array('class' => 'contactselector mdl-align'));
@@ -117,14 +117,14 @@ function message_print_contact_selector($countunreadtotal, $viewing, $user1, $us
         $strunreadmessages = get_string('unreadmessages','message', $countunreadtotal);
     }
 
-    message_print_usergroup_selector($viewing, $courses, $coursecontexts, $countunreadtotal, count($blockedusers), $strunreadmessages);
+    message_print_usergroup_selector($viewing, $courses, $coursecontexts, $countunreadtotal, count($blockedusers), $strunreadmessages, $user1);
 
     if ($viewing == MESSAGE_VIEW_UNREAD_MESSAGES) {
-        message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $PAGE->url, 1, $showcontactactionlinks,$strunreadmessages, $user2);
+        message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $PAGE->url, 1, $showactionlinks,$strunreadmessages, $user2);
     } else if ($viewing == MESSAGE_VIEW_CONTACTS || $viewing == MESSAGE_VIEW_SEARCH || $viewing == MESSAGE_VIEW_RECENT_CONVERSATIONS || $viewing == MESSAGE_VIEW_RECENT_NOTIFICATIONS) {
-        message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $PAGE->url, 0, $showcontactactionlinks, $strunreadmessages, $user2);
+        message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $PAGE->url, 0, $showactionlinks, $strunreadmessages, $user2);
     } else if ($viewing == MESSAGE_VIEW_BLOCKED) {
-        message_print_blocked_users($blockedusers, $PAGE->url, $showcontactactionlinks, null, $user2);
+        message_print_blocked_users($blockedusers, $PAGE->url, $showactionlinks, null, $user2);
     } else if (substr($viewing, 0, 7) == MESSAGE_VIEW_COURSE) {
         $courseidtoshow = intval(substr($viewing, 7));
 
@@ -132,24 +132,28 @@ function message_print_contact_selector($countunreadtotal, $viewing, $user1, $us
             && array_key_exists($courseidtoshow, $coursecontexts)
             && has_capability('moodle/course:viewparticipants', $coursecontexts[$courseidtoshow])) {
 
-            message_print_participants($coursecontexts[$courseidtoshow], $courseidtoshow, $PAGE->url, $showcontactactionlinks, null, $page, $user2);
+            message_print_participants($coursecontexts[$courseidtoshow], $courseidtoshow, $PAGE->url, $showactionlinks, null, $page, $user2);
         } else {
             //shouldn't get here. User trying to access a course they're not in perhaps.
             add_to_log(SITEID, 'message', 'view', 'index.php', $viewing);
         }
     }
 
-    echo html_writer::start_tag('form', array('action' => 'index.php','method' => 'GET'));
-    echo html_writer::start_tag('fieldset');
-    $managebuttonclass = 'visible';
-    if ($viewing == MESSAGE_VIEW_SEARCH) {
-        $managebuttonclass = 'hiddenelement';
+    // Only show the search button if we're viewing our own messages.
+    // Search isn't currently able to deal with user A wanting to search user B's messages.
+    if ($showactionlinks) {
+        echo html_writer::start_tag('form', array('action' => 'index.php','method' => 'GET'));
+        echo html_writer::start_tag('fieldset');
+        $managebuttonclass = 'visible';
+        if ($viewing == MESSAGE_VIEW_SEARCH) {
+            $managebuttonclass = 'hiddenelement';
+        }
+        $strmanagecontacts = get_string('search','message');
+        echo html_writer::empty_tag('input', array('type' => 'hidden','name' => 'viewing','value' => MESSAGE_VIEW_SEARCH));
+        echo html_writer::empty_tag('input', array('type' => 'submit','value' => $strmanagecontacts,'class' => $managebuttonclass));
+        echo html_writer::end_tag('fieldset');
+        echo html_writer::end_tag('form');
     }
-    $strmanagecontacts = get_string('search','message');
-    echo html_writer::empty_tag('input', array('type' => 'hidden','name' => 'viewing','value' => MESSAGE_VIEW_SEARCH));
-    echo html_writer::empty_tag('input', array('type' => 'submit','value' => $strmanagecontacts,'class' => $managebuttonclass));
-    echo html_writer::end_tag('fieldset');
-    echo html_writer::end_tag('form');
 
     echo html_writer::end_tag('div');
 }
@@ -416,7 +420,7 @@ function message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $
     }
 
     if($countonlinecontacts) {
-        /// print out list of online contacts
+        // Print out list of online contacts.
 
         if (empty($titletodisplay)) {
             message_print_heading(get_string('onlinecontacts', 'message', $countonlinecontacts));
@@ -432,7 +436,7 @@ function message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $
     }
 
     if ($countofflinecontacts) {
-        /// print out list of offline contacts
+        // Print out list of offline contacts.
 
         if (empty($titletodisplay)) {
             message_print_heading(get_string('offlinecontacts', 'message', $countofflinecontacts));
@@ -448,7 +452,7 @@ function message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $
 
     }
 
-    /// print out list of incoming contacts
+    // Print out list of incoming contacts.
     if ($countstrangers) {
         message_print_heading(get_string('incomingcontacts', 'message', $countstrangers));
 
@@ -477,10 +481,11 @@ function message_print_contacts($onlinecontacts, $offlinecontacts, $strangers, $
  * @param array $coursecontexts array of course contexts. Keyed on course id.
  * @param int $countunreadtotal how many unread messages does the user have?
  * @param int $countblocked how many users has the current user blocked?
+ * @param stdClass $user1 The user whose messages we are viewing.
  * @param string $strunreadmessages a preconstructed message about the number of unread messages the user has
  * @return void
  */
-function message_print_usergroup_selector($viewing, $courses, $coursecontexts, $countunreadtotal, $countblocked, $strunreadmessages) {
+function message_print_usergroup_selector($viewing, $courses, $coursecontexts, $countunreadtotal, $countblocked, $strunreadmessages, $user1 = null) {
     $options = array();
 
     if ($countunreadtotal>0) { //if there are unread messages
@@ -520,6 +525,9 @@ function message_print_usergroup_selector($viewing, $courses, $coursecontexts, $
 
     echo html_writer::start_tag('form', array('id' => 'usergroupform','method' => 'get','action' => ''));
     echo html_writer::start_tag('fieldset');
+    if ( !empty($user1) && !empty($user1->id) ) {
+        echo html_writer::empty_tag('input', array('type' => 'hidden','name' => 'user1','value' => $user1->id));
+    }
     echo html_writer::label(get_string('messagenavigation', 'message'), 'viewing');
     echo html_writer::select($options, 'viewing', $viewing, false, array('id' => 'viewing','onchange' => 'this.form.submit()'));
     echo html_writer::end_tag('fieldset');
@@ -799,27 +807,27 @@ function message_get_recent_notifications($user, $limitfrom=0, $limitto=100) {
  * @param stdClass $user the current user
  * @param bool $showicontext flag indicating whether or not to show text next to the action icons
  */
-function message_print_recent_conversations($user=null, $showicontext=false) {
+function message_print_recent_conversations($user1 = null, $showicontext = false, $showactionlinks = true) {
     global $USER;
 
     echo html_writer::start_tag('p', array('class' => 'heading'));
     echo get_string('mostrecentconversations', 'message');
     echo html_writer::end_tag('p');
 
-    if (empty($user)) {
-        $user = $USER;
+    if (empty($user1)) {
+        $user1 = $USER;
     }
 
-    $conversations = message_get_recent_conversations($user);
+    $conversations = message_get_recent_conversations($user1);
 
     // Attach context url information to create the "View this conversation" type links
     foreach($conversations as $conversation) {
-        $conversation->contexturl = new moodle_url("/message/index.php?user2={$conversation->id}");
+        $conversation->contexturl = new moodle_url("/message/index.php?user1={$user1->id}&user2={$conversation->id}");
         $conversation->contexturlname = get_string('thisconversation', 'message');
     }
 
     $showotheruser = true;
-    message_print_recent_messages_table($conversations, $user, $showotheruser, $showicontext);
+    message_print_recent_messages_table($conversations, $user1, $showotheruser, $showicontext, false, $showactionlinks);
 }
 
 /**
@@ -854,7 +862,7 @@ function message_print_recent_notifications($user=null) {
  * @param bool $showicontext show text next to the action icons?
  * @return void
  */
-function message_print_recent_messages_table($messages, $user=null, $showotheruser=true, $showicontext=false) {
+function message_print_recent_messages_table($messages, $user = null, $showotheruser = true, $showicontext = false, $forcetexttohtml = false, $showactionlinks = true) {
     global $OUTPUT;
     static $dateformat;
 
@@ -867,26 +875,29 @@ function message_print_recent_messages_table($messages, $user=null, $showotherus
         echo html_writer::start_tag('div', array('class' => 'singlemessage'));
 
         if ($showotheruser) {
-            if ( $message->contactlistid )  {
-                if ($message->blocked == 0) { /// not blocked
-                    $strcontact = message_contact_link($message->id, 'remove', true, null, $showicontext);
-                    $strblock   = message_contact_link($message->id, 'block', true, null, $showicontext);
-                } else { // blocked
+            $strcontact = $strblock = $strhistory = null;
+
+            if ($showactionlinks) {
+                if ( $message->contactlistid )  {
+                    if ($message->blocked == 0) { // The other user isn't blocked.
+                        $strcontact = message_contact_link($message->id, 'remove', true, null, $showicontext);
+                        $strblock   = message_contact_link($message->id, 'block', true, null, $showicontext);
+                    } else { // The other user is blocked.
+                        $strcontact = message_contact_link($message->id, 'add', true, null, $showicontext);
+                        $strblock   = message_contact_link($message->id, 'unblock', true, null, $showicontext);
+                    }
+                } else {
                     $strcontact = message_contact_link($message->id, 'add', true, null, $showicontext);
-                    $strblock   = message_contact_link($message->id, 'unblock', true, null, $showicontext);
+                    $strblock   = message_contact_link($message->id, 'block', true, null, $showicontext);
                 }
-            } else {
-                $strcontact = message_contact_link($message->id, 'add', true, null, $showicontext);
-                $strblock   = message_contact_link($message->id, 'block', true, null, $showicontext);
-            }
 
-            //should we show just the icon or icon and text?
-            $histicontext = 'icon';
-            if ($showicontext) {
-                $histicontext = 'both';
+                //should we show just the icon or icon and text?
+                $histicontext = 'icon';
+                if ($showicontext) {
+                    $histicontext = 'both';
+                }
+                $strhistory = message_history_link($user->id, $message->id, true, '', '', $histicontext);
             }
-            $strhistory = message_history_link($user->id, $message->id, true, '', '', $histicontext);
-
             echo html_writer::start_tag('span', array('class' => 'otheruser'));
 
             echo html_writer::start_tag('span', array('class' => 'pix'));
@@ -895,13 +906,15 @@ function message_print_recent_messages_table($messages, $user=null, $showotherus
 
             echo html_writer::start_tag('span', array('class' => 'contact'));
 
-            $link = new moodle_url("/message/index.php?id=$message->id");
+            $link = new moodle_url("/message/index.php?user1={$user->id}&user2=$message->id");
             $action = null;
             echo $OUTPUT->action_link($link, fullname($message), $action, array('title' => get_string('sendmessageto', 'message', fullname($message))));
 
             echo html_writer::end_tag('span');//end contact
 
-            echo $strcontact.$strblock.$strhistory;
+            if ($showactionlinks) {
+                echo $strcontact.$strblock.$strhistory;
+            }
             echo html_writer::end_tag('span');//end otheruser
         }
         $messagetoprint = null;
@@ -935,19 +948,19 @@ function message_add_contact($contactid, $blocked=0) {
     }
 
     if (($contact = $DB->get_record('message_contacts', array('userid' => $USER->id, 'contactid' => $contactid))) !== false) {
-    /// record already exists - we may be changing blocking status
+    // A record already exists. We may be changing blocking status.
 
         if ($contact->blocked !== $blocked) {
-        /// change to blocking status
+            // Blocking status has been changed.
             $contact->blocked = $blocked;
             return $DB->update_record('message_contacts', $contact);
         } else {
-        /// no changes to blocking status
+            // No change to blocking status.
             return true;
         }
 
     } else {
-    /// new contact record
+        // New contact record.
         $contact = new stdClass();
         $contact->userid = $USER->id;
         $contact->contactid = $contactid;
@@ -1025,7 +1038,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
         $personsearchstring = $frm->combinedsearch;
     }
 
-    /// search for person
+    // Search for person.
     if ($personsearch) {
         if (optional_param('mycourses', 0, PARAM_BOOL)) {
             $users = array();
@@ -1048,7 +1061,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
             foreach ($users as $user) {
 
                 if ( $user->contactlistid )  {
-                    if ($user->blocked == 0) { /// not blocked
+                    if ($user->blocked == 0) { // User is not blocked.
                         $strcontact = message_contact_link($user->id, 'remove', true, null, $showicontext);
                         $strblock   = message_contact_link($user->id, 'block', true, null, $showicontext);
                     } else { // blocked
@@ -1060,7 +1073,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
                     $strblock   = message_contact_link($user->id, 'block', true, null, $showicontext);
                 }
 
-                //should we show just the icon or icon and text?
+                // Should we show just the icon or icon and text?
                 $histicontext = 'icon';
                 if ($showicontext) {
                     $histicontext = 'both';
@@ -1143,12 +1156,12 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
 
         if (($messages = message_search($keywords, $fromme, $tome, $courseid)) !== false) {
 
-        /// get a list of contacts
+            // Get a list of contacts.
             if (($contacts = $DB->get_records('message_contacts', array('userid' => $USER->id), '', 'contactid, blocked') ) === false) {
                 $contacts = array();
             }
 
-        /// print heading with number of results
+            // Print heading with number of results.
             echo html_writer::start_tag('p', array('class' => 'heading searchresultcount'));
             $countresults = count($messages);
             if ($countresults == MESSAGE_SEARCH_MAX_RESULTS) {
@@ -1158,7 +1171,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
             }
             echo html_writer::end_tag('p');
 
-        /// print table headings
+            // Print table headings.
             echo html_writer::start_tag('table', array('class' => 'messagesearchresults', 'cellspacing' => '0'));
 
             $headertdstart = html_writer::start_tag('td', array('class' => 'messagesearchresultscol'));
@@ -1175,7 +1188,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
             $strcontext = get_string('context', 'message');
             foreach ($messages as $message) {
 
-            /// ignore messages to and from blocked users unless $frm->includeblocked is set
+                // Ignore messages to and from blocked users unless $frm->includeblocked is set.
                 if (!optional_param('includeblocked', 0, PARAM_BOOL) and (
                       ( isset($contacts[$message->useridfrom]) and ($contacts[$message->useridfrom]->blocked == 1)) or
                       ( isset($contacts[$message->useridto]  ) and ($contacts[$message->useridto]->blocked   == 1))
@@ -1185,7 +1198,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
                     continue;
                 }
 
-            /// load up user to record
+                // Load user-to record.
                 if ($message->useridto !== $USER->id) {
                     $userto = $DB->get_record('user', array('id' => $message->useridto));
                     $tocontact = (array_key_exists($message->useridto, $contacts) and
@@ -1198,7 +1211,7 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
                     $toblocked = false;
                 }
 
-            /// load up user from record
+                // Load user-from record.
                 if ($message->useridfrom !== $USER->id) {
                     $userfrom = $DB->get_record('user', array('id' => $message->useridfrom));
                     $fromcontact = (array_key_exists($message->useridfrom, $contacts) and
@@ -1211,11 +1224,11 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
                     $fromblocked = false;
                 }
 
-            /// find date string for this message
+                // Find date string for this message.
                 $date = usergetdate($message->timecreated);
                 $datestring = $date['year'].$date['mon'].$date['mday'];
 
-            /// print out message row
+                // Print out message row.
                 echo html_writer::start_tag('tr', array('valign' => 'top'));
 
                 echo html_writer::start_tag('td', array('class' => 'contact'));
@@ -1230,8 +1243,8 @@ function message_print_search_results($frm, $showicontext=false, $currentuser=nu
                 echo message_get_fragment($message->smallmessage, $keywords);
                 echo html_writer::start_tag('div', array('class' => 'link'));
 
-                //If the user clicks the context link display message sender on the left
-                //EXCEPT if the current user is in the conversation. Current user == always on the left
+                // If the user clicks the context link display message sender on the left.
+                // EXCEPT if the current user is in the conversation. Current user == always on the left.
                 $leftsideuserid = $rightsideuserid = null;
                 if ($currentuser->id == $message->useridto) {
                     $leftsideuserid = $message->useridto;
@@ -1518,7 +1531,10 @@ function message_search_users($courseid, $searchtext, $sort='', $exceptions='')
 }
 
 /**
- * search a user's messages
+ * Search a user's messages
+ *
+ * Returns a list of posts found using an array of search terms
+ * eg   word  +word -word
  *
  * @param array $searchterms an array of search terms (strings)
  * @param bool $fromme include messages from the user?
@@ -1528,9 +1544,6 @@ function message_search_users($courseid, $searchtext, $sort='', $exceptions='')
  * @return mixed An array of messages or false if no matching messages were found
  */
 function message_search($searchterms, $fromme=true, $tome=true, $courseid='none', $userid=0) {
-/// Returns a list of posts found using an array of search terms
-/// eg   word  +word -word
-///
     global $CFG, $USER, $DB;
 
     // If user is searching all messages check they are allowed to before doing anything else
@@ -1538,10 +1551,10 @@ function message_search($searchterms, $fromme=true, $tome=true, $courseid='none'
         print_error('accessdenied','admin');
     }
 
-    /// If no userid sent then assume current user
+    // If no userid sent then assume current user.
     if ($userid == 0) $userid = $USER->id;
 
-    /// Some differences in SQL syntax
+    // Some differences in SQL syntax.
     if ($DB->sql_regex_supported()) {
         $REGEXP    = $DB->sql_regex(true);
         $NOTREGEXP = $DB->sql_regex(false);
@@ -1551,8 +1564,8 @@ function message_search($searchterms, $fromme=true, $tome=true, $courseid='none'
     $params = array();
     $i = 0;
 
-    //preprocess search terms to check whether we have at least 1 eligible search term
-    //if we do we can drop words around it like 'a'
+    // Preprocess search terms to check whether we have at least 1 eligible search term.
+    // If we do we can drop words around it like 'a'.
     $dropshortwords = false;
     foreach ($searchterms as $searchterm) {
         if (strlen($searchterm) >= 2) {
@@ -1563,13 +1576,12 @@ function message_search($searchterms, $fromme=true, $tome=true, $courseid='none'
     foreach ($searchterms as $searchterm) {
         $i++;
 
-        $NOT = false; /// Initially we aren't going to perform NOT LIKE searches, only MSSQL and Oracle
+        $NOT = false; // Initially we aren't going to perform NOT LIKE searches, only MSSQL and Oracle.
 
         if ($dropshortwords && strlen($searchterm) < 2) {
             continue;
         }
-    /// Under Oracle and MSSQL, trim the + and - operators and perform
-    /// simpler LIKE search
+        // Under Oracle and MSSQL, trim the + and - operators and perform simpler LIKE search.
         if (!$DB->sql_regex_supported()) {
             if (substr($searchterm, 0, 1) == '-') {
                 $NOT = true;
@@ -1602,16 +1614,16 @@ function message_search($searchterms, $fromme=true, $tome=true, $courseid='none'
         $searchcond = implode(" AND ", $searchcond);
     }
 
-    /// There are several possibilities
-    /// 1. courseid = SITEID : The admin is searching messages by all users
-    /// 2. courseid = ??     : A teacher is searching messages by users in
-    ///                        one of their courses - currently disabled
-    /// 3. courseid = none   : User is searching their own messages;
-    ///    a.  Messages from user
-    ///    b.  Messages to user
-    ///    c.  Messages to and from user
+    // There are several possibilities
+    // 1. courseid = SITEID : The admin is searching messages by all users
+    // 2. courseid = ??     : A teacher is searching messages by users in
+    //                        one of their courses - currently disabled
+    // 3. courseid = none   : User is searching their own messages;
+    //    a.  Messages from user
+    //    b.  Messages to user
+    //    c.  Messages to and from user
 
-    if ($courseid == SITEID) { /// admin is searching all messages
+    if ($courseid == SITEID) { // Admin is searching all messages.
         $m_read   = $DB->get_records_sql("SELECT m.id, m.useridto, m.useridfrom, m.smallmessage, m.fullmessage, m.timecreated
                                             FROM {message_read} m
                                            WHERE $searchcond", $params, 0, MESSAGE_SEARCH_MAX_RESULTS);
@@ -1620,7 +1632,7 @@ function message_search($searchterms, $fromme=true, $tome=true, $courseid='none'
                                            WHERE $searchcond", $params, 0, MESSAGE_SEARCH_MAX_RESULTS);
 
     } else if ($courseid !== 'none') {
-        /// This has not been implemented due to security concerns
+        // This has not been implemented due to security concerns.
         $m_read   = array();
         $m_unread = array();
 
@@ -1835,7 +1847,7 @@ function message_get_history($user1, $user2, $limitnum=0, $viewingnewmessages=fa
  * @param string $messagehistorylink the html for the message history link or false
  * @param bool $viewingnewmessages are we currently viewing new messages?
  */
-function message_print_message_history($user1,$user2,$search='',$messagelimit=0, $messagehistorylink=false, $viewingnewmessages=false) {
+function message_print_message_history($user1, $user2 ,$search = '', $messagelimit = 0, $messagehistorylink = false, $viewingnewmessages = false, $showactionlinks = true) {
     global $CFG, $OUTPUT;
 
     echo $OUTPUT->box_start('center');
@@ -1856,16 +1868,14 @@ function message_print_message_history($user1,$user2,$search='',$messagelimit=0,
     echo $OUTPUT->user_picture($user2, array('size' => 100, 'courseid' => SITEID));
     echo html_writer::tag('div', fullname($user2), array('class' => 'heading'));
 
-    if (isset($user2->iscontact) && isset($user2->isblocked)) {
-        $incontactlist = $user2->iscontact;
-        $isblocked = $user2->isblocked;
+    if ($showactionlinks && isset($user2->iscontact) && isset($user2->isblocked)) {
 
         $script = null;
         $text = true;
         $icon = false;
 
-        $strcontact = message_get_contact_add_remove_link($incontactlist, $isblocked, $user2, $script, $text, $icon);
-        $strblock   = message_get_contact_block_link($incontactlist, $isblocked, $user2, $script, $text, $icon);
+        $strcontact = message_get_contact_add_remove_link($user2->iscontact, $user2->isblocked, $user2, $script, $text, $icon);
+        $strblock   = message_get_contact_block_link($user2->iscontact, $user2->isblocked, $user2, $script, $text, $icon);
         $useractionlinks = $strcontact.'&nbsp;|'.$strblock;
 
         echo html_writer::tag('div', $useractionlinks, array('class' => 'useractionlinks'));
@@ -2068,7 +2078,7 @@ function message_print_contactlist_user($contact, $incontactlist = true, $isbloc
         $linkclass = 'messageselecteduser';
     }
 
-    /// are there any unread messages for this contact?
+    // Are there any unread messages for this contact?
     if ($contact->messagecount > 0 ){
         $fullnamelink = '<strong>'.$fullnamelink.' ('.$contact->messagecount.')</strong>';
     }
index 6510353..ea027e0 100644 (file)
@@ -141,7 +141,9 @@ class assign_feedback_comments extends assign_feedback_plugin {
             }
         }
 
-        $mform->addElement('editor', 'assignfeedbackcomments_editor', '', null, null);
+        $mform->addElement('editor', 'assignfeedbackcomments_editor', html_writer::tag('span', $this->get_name(),
+            array('class' => 'accesshide')), null, null);
+
         return true;
     }
 
index f019f8e..57c413b 100644 (file)
@@ -94,8 +94,8 @@ class assign_feedback_file extends assign_feedback_plugin {
                                                   'assignfeedback_file',
                                                   ASSIGNFEEDBACK_FILE_FILEAREA,
                                                   $gradeid);
-
-        $mform->addElement('filemanager', $elementname . '_filemanager', '', null, $fileoptions);
+        $mform->addElement('filemanager', $elementname . '_filemanager', html_writer::tag('span', $this->get_name(),
+            array('class' => 'accesshide')), null, $fileoptions);
 
         return true;
     }
index 92490ec..2058830 100644 (file)
@@ -326,7 +326,7 @@ function assign_print_overview($courses, &$htmlarray) {
     // get all user submissions, indexed by assignment id
     $mysubmissions = $DB->get_records_sql("SELECT a.id AS assignment, a.nosubmissions AS nosubmissions, g.timemodified AS timemarked, g.grader AS grader, g.grade AS grade, s.status AS status
                             FROM {assign} a LEFT JOIN {assign_grades} g ON g.assignment = a.id AND g.userid = ? LEFT JOIN {assign_submission} s ON s.assignment = a.id AND s.userid = ?
-                            AND a.id $sqlassignmentids", array_merge(array($USER->id, $USER->id), $assignmentidparams));
+                            WHERE a.id $sqlassignmentids", array_merge(array($USER->id, $USER->id), $assignmentidparams));
 
     foreach ($assignments as $assignment) {
         // Do not show assignments that are not open
index 5844463..671236c 100644 (file)
@@ -51,15 +51,6 @@ function assignsubmission_comments_comment_validate(stdClass $options) {
     if (!has_capability('mod/assign:grade', $context)) {
         if (!has_capability('mod/assign:submit', $context)) {
             throw new comment_exception('nopermissiontocomment');
-        } else if ($assignment->get_instance()->teamsubmission) {
-            $group = $assignment->get_submission_group($USER->id);
-            $groupid = 0;
-            if ($group) {
-                $groupid = $group->id;
-            }
-            if ($groupid != $submission->groupid) {
-                throw new comment_exception('nopermissiontocomment');
-            }
         } else if ($submission->userid != $USER->id) {
             throw new comment_exception('nopermissiontocomment');
         }
@@ -95,15 +86,6 @@ function assignsubmission_comments_comment_permissions(stdClass $options) {
     if (!has_capability('mod/assign:grade', $context)) {
         if (!has_capability('mod/assign:submit', $context)) {
             return array('post' => false, 'view' => false);
-        } else if ($assignment->get_instance()->teamsubmission) {
-            $group = $assignment->get_submission_group($USER->id);
-            $groupid = 0;
-            if ($group) {
-                $groupid = $group->id;
-            }
-            if ($groupid != $submission->groupid) {
-                return array('post' => false, 'view' => false);
-            }
         } else if ($submission->userid != $USER->id) {
             return array('post' => false, 'view' => false);
         }
index 1d91186..addc361 100644 (file)
@@ -113,7 +113,12 @@ class assign_submission_comments extends assign_submission_plugin {
      * @return bool was it a success? (false will trigger a rollback)
      */
     public function upgrade_settings(context $oldcontext, stdClass $oldassignment, & $log) {
-        // first upgrade settings (nothing to do)
+        if ($oldassignment->assignmenttype == 'upload') {
+            // Disable if allow notes was not enabled.
+            if (!$oldassignment->var2) {
+                $this->disable();
+            }
+        }
         return true;
     }
 
index ed1e234..833b0a6 100644 (file)
@@ -150,9 +150,10 @@ class assign_submission_file extends assign_submission_plugin {
         $fileoptions = $this->get_file_options();
         $submissionid = $submission ? $submission->id : 0;
 
-
         $data = file_prepare_standard_filemanager($data, 'files', $fileoptions, $this->assignment->get_context(), 'assignsubmission_file', ASSIGNSUBMISSION_FILE_FILEAREA, $submissionid);
-        $mform->addElement('filemanager', 'files_filemanager', '', null, $fileoptions);
+        $mform->addElement('filemanager', 'files_filemanager', html_writer::tag('span', $this->get_name(),
+            array('class' => 'accesshide')), null, $fileoptions);
+
         return true;
     }
 
@@ -301,14 +302,31 @@ class assign_submission_file extends assign_submission_plugin {
      * @return bool Was it a success? (false will trigger rollback)
      */
     public function upgrade_settings(context $oldcontext,stdClass $oldassignment, & $log) {
+        global $DB;
+
         if ($oldassignment->assignmenttype == 'uploadsingle') {
             $this->set_config('maxfilesubmissions', 1);
             $this->set_config('maxsubmissionsizebytes', $oldassignment->maxbytes);
             return true;
-        }else {
-
+        } else if ($oldassignment->assignmenttype == 'upload') {
             $this->set_config('maxfilesubmissions', $oldassignment->var1);
             $this->set_config('maxsubmissionsizebytes', $oldassignment->maxbytes);
+
+            // Advanced file upload uses a different setting to do the same thing.
+            $DB->set_field('assign',
+                           'submissiondrafts',
+                           $oldassignment->var4,
+                           array('id'=>$this->assignment->get_instance()->id));
+
+            // Convert advanced file upload "hide description before due date" setting.
+            $alwaysshow = 0;
+            if (!$oldassignment->var3) {
+                $alwaysshow = 1;
+            }
+            $DB->set_field('assign',
+                           'alwaysshowdescription',
+                           $alwaysshow,
+                           array('id'=>$this->assignment->get_instance()->id));
             return true;
         }
 
index 7d5b624..f744bc2 100644 (file)
@@ -90,9 +90,10 @@ class assign_submission_onlinetext extends assign_submission_plugin {
 
         }
 
-
         $data = file_prepare_standard_editor($data, 'onlinetext', $editoroptions, $this->assignment->get_context(), 'assignsubmission_onlinetext', ASSIGNSUBMISSION_ONLINETEXT_FILEAREA, $submissionid);
-        $mform->addElement('editor', 'onlinetext_editor', '', null, $editoroptions);
+        $mform->addElement('editor', 'onlinetext_editor', html_writer::tag('span', $this->get_name(),
+            array('class' => 'accesshide')), null, $editoroptions);
+
         return true;
     }
 
index f50aac0..89f15a2 100644 (file)
@@ -156,6 +156,20 @@ class assign_upgrade_manager {
                 $gradingdefinitions = $DB->get_records('grading_definitions', array('areaid'=>$gradingarea->id));
             }
 
+            // Upgrade availability data.
+            $DB->set_field('course_modules_availability',
+                           'coursemoduleid',
+                           $newcoursemodule->id,
+                           array('coursemoduleid'=>$oldcoursemodule->id));
+            $DB->set_field('course_modules_availability',
+                           'sourcecmid',
+                           $newcoursemodule->id,
+                           array('sourcecmid'=>$oldcoursemodule->id));
+            $DB->set_field('course_sections_availability',
+                           'sourcecmid',
+                           $newcoursemodule->id,
+                           array('sourcecmid'=>$oldcoursemodule->id));
+
             // upgrade completion data
             $DB->set_field('course_modules_completion', 'coursemoduleid', $newcoursemodule->id, array('coursemoduleid'=>$oldcoursemodule->id));
             $allcriteria = $DB->get_records('course_completion_criteria', array('moduleinstance'=>$oldcoursemodule->id));
index e4a0b8a..7cf39cb 100644 (file)
@@ -453,13 +453,24 @@ function feedback_get_recent_mod_activity(&$activities, &$index,
         $tmpactivity->sectionnum= $cm->sectionnum;
         $tmpactivity->timestamp = $feedbackitem->timemodified;
 
+        $tmpactivity->content = new stdClass();
         $tmpactivity->content->feedbackid = $feedbackitem->id;
         $tmpactivity->content->feedbackuserid = $feedbackitem->userid;
 
-        //TODO: add all necessary user fields, this is not enough for user_picture
-        $tmpactivity->user->userid   = $feedbackitem->userid;
+        $userfields = explode(',', user_picture::fields());
+        $tmpactivity->user = new stdClass();
+        foreach ($userfields as $userfield) {
+            if ($userfield == 'id') {
+                $tmpactivity->user->{$userfield} = $feedbackitem->userid; // aliased in SQL above
+            } else {
+                if (!empty($feedbackitem->{$userfield})) {
+                    $tmpactivity->user->{$userfield} = $feedbackitem->{$userfield};
+                } else {
+                    $tmpactivity->user->{$userfield} = null;
+                }
+            }
+        }
         $tmpactivity->user->fullname = fullname($feedbackitem, $viewfullnames);
-        $tmpactivity->user->picture  = $feedbackitem->picture;
 
         $activities[$index++] = $tmpactivity;
     }
@@ -500,7 +511,7 @@ function feedback_print_recent_mod_activity($activity, $courseid, $detail, $modn
     echo '</div>';
 
     echo '<div class="user">';
-    echo "<a href=\"$CFG->wwwroot/user/view.php?id={$activity->user->userid}&amp;course=$courseid\">"
+    echo "<a href=\"$CFG->wwwroot/user/view.php?id={$activity->user->id}&amp;course=$courseid\">"
          ."{$activity->user->fullname}</a> - ".userdate($activity->timestamp);
     echo '</div>';
 
index ea00ab2..903c9a1 100644 (file)
@@ -112,6 +112,7 @@ class restore_forum_activity_task extends restore_activity_task {
         $rules[] = new restore_log_rule('forum', 'delete discussion', 'view.php?id={course_module}', '{forum}');
         $rules[] = new restore_log_rule('forum', 'add post', 'discuss.php?d={forum_discussion}&parent={forum_post}', '{forum_post}');
         $rules[] = new restore_log_rule('forum', 'update post', 'discuss.php?d={forum_discussion}#p{forum_post}&parent={forum_post}', '{forum_post}');
+        $rules[] = new restore_log_rule('forum', 'update post', 'discuss.php?d={forum_discussion}&parent={forum_post}', '{forum_post}');
         $rules[] = new restore_log_rule('forum', 'prune post', 'discuss.php?d={forum_discussion}', '{forum_post}');
         $rules[] = new restore_log_rule('forum', 'delete post', 'discuss.php?d={forum_discussion}', '[post]');
 
index 79259e1..ccef8dc 100644 (file)
@@ -2956,7 +2956,7 @@ function forum_subscribed_users($course, $forum, $groupid=0, $context = null, $f
  */
 function forum_get_course_forum($courseid, $type) {
 // How to set up special 1-per-course forums
-    global $CFG, $DB, $OUTPUT;
+    global $CFG, $DB, $OUTPUT, $USER;
 
     if ($forums = $DB->get_records_select("forum", "course = ? AND type = ?", array($courseid, $type), "id ASC")) {
         // There should always only be ONE, but with the right combination of
@@ -2970,6 +2970,9 @@ function forum_get_course_forum($courseid, $type) {
     $forum = new stdClass();
     $forum->course = $courseid;
     $forum->type = "$type";
+    if (!empty($USER->htmleditor)) {
+        $forum->introformat = $USER->htmleditor;
+    }
     switch ($forum->type) {
         case "news":
             $forum->name  = get_string("namenews", "forum");
index d751340..a16f2a2 100644 (file)
@@ -524,7 +524,7 @@ class qformat_default {
     }
 
 
-    function readquestion($lines) {
+    protected function readquestion($lines) {
     /// Given an array of lines known to define a question in
     /// this format, this function converts it into a question
     /// object suitable for processing and insertion into Moodle.
index 11d8e78..20f1a31 100644 (file)
@@ -2309,9 +2309,14 @@ abstract class lesson_page extends lesson_base {
         }
         if (count($this->answers)>0) {
             $count = 0;
+            $qtype = $properties->qtype;
             foreach ($this->answers as $answer) {
-                $properties->{'answer_editor['.$count.']'} = array('text'=>$answer->answer, 'format'=>$answer->answerformat);
-                $properties->{'response_editor['.$count.']'} = array('text'=>$answer->response, 'format'=>$answer->responseformat);
+                $properties->{'answer_editor['.$count.']'} = array('text' => $answer->answer, 'format' => $answer->answerformat);
+                if ($qtype != LESSON_PAGE_MATCHING) {
+                    $properties->{'response_editor['.$count.']'} = array('text' => $answer->response, 'format' => $answer->responseformat);
+                } else {
+                    $properties->{'response_editor['.$count.']'} = $answer->response;
+                }
                 $properties->{'jumpto['.$count.']'} = $answer->jumpto;
                 $properties->{'score['.$count.']'} = $answer->score;
                 $count++;
index 78323ec..9e9b42c 100644 (file)
@@ -213,6 +213,7 @@ class lesson_page_type_essay extends lesson_page {
             } else {
                 $essayinfo = new stdClass();
                 $essayinfo->answer = get_string("didnotanswerquestion", "lesson");
+                $essayinfo->answerformat = null;
             }
 
             if (isset($pagestats[$this->properties->id])) {
index be4be19..09cdf47 100644 (file)
@@ -72,16 +72,17 @@ class lesson_page_type_matching extends lesson_page {
         foreach ($answers as $answer) {
             // get all the response
             if ($answer->response != NULL) {
-                $responses[] = trim($answer->response);
+                $responses[$answer->id] = trim($answer->response);
             }
         }
 
         $responseoptions = array(''=>get_string('choosedots'));
         if (!empty($responses)) {
-            shuffle($responses);
-            $responses = array_unique($responses);
-            foreach ($responses as $response) {
-                $responseoptions[htmlspecialchars(trim($response))] = $response;
+            $shuffleresponses = $responses;
+            shuffle($shuffleresponses);
+            foreach ($shuffleresponses as  $response) {
+                $key = array_search($response, $responses);
+                $responseoptions[$key] = $response;
             }
         }
         if (isset($USER->modattempts[$this->lesson->id]) && !empty($attempt->useranswer)) {
@@ -115,9 +116,9 @@ class lesson_page_type_matching extends lesson_page {
                 $answer->answer = $properties->answer_editor[$i]['text'];
                 $answer->answerformat = $properties->answer_editor[$i]['format'];
             }
-            if (!empty($properties->response_editor[$i]) && is_array($properties->response_editor[$i])) {
-                $answer->response = $properties->response_editor[$i]['text'];
-                $answer->responseformat = $properties->response_editor[$i]['format'];
+            if (!empty($properties->response_editor[$i])) {
+                $answer->response = $properties->response_editor[$i];
+                $answer->responseformat = 0;
             }
 
             if (isset($properties->jumpto[$i])) {
@@ -171,27 +172,26 @@ class lesson_page_type_matching extends lesson_page {
         $wrong   = array_shift($answers);
 
         foreach ($answers as $key=>$answer) {
-            if ($answer->answer === '' or $answer->response === '') {
-                // incomplete option!
-                unset($answers[$key]);
+            if ($answer->answer !== '' or $answer->response !== '') {
+                $answers[$answer->id] = $answer;
             }
+            unset($answers[$key]);
         }
         // get he users exact responses for record keeping
         $hits = 0;
         $userresponse = array();
-        foreach ($response as $key => $value) {
-            foreach($answers as $answer) {
-                if ($value === $answer->response) {
-                    $userresponse[] = $answer->id;
-                }
-                if ((int)$answer->id === (int)$key) {
-                    $result->studentanswer .= '<br />'.format_text($answer->answer, $answer->answerformat, $formattextdefoptions).' = '.$value;
-                }
-                if ((int)$answer->id === (int)$key and $value === $answer->response) {
+        foreach ($response as $id => $value) {
+            $userresponse[] = $value;
+            // Make sure the user's answer is exist in question's answer
+            if (array_key_exists($id, $answers)) {
+                $answer = $answers[$id];
+                $result->studentanswer .= '<br />'.format_text($answer->answer, $answer->answerformat, $formattextdefoptions).' = '.$answers[$value]->response;
+                if ($id == $value) {
                     $hits++;
                 }
             }
         }
+
         $result->userresponse = implode(",", $userresponse);
 
         if ($hits == count($answers)) {
@@ -315,9 +315,9 @@ class lesson_page_type_matching extends lesson_page {
                 $this->answers[$i]->answer = $properties->answer_editor[$i]['text'];
                 $this->answers[$i]->answerformat = $properties->answer_editor[$i]['format'];
             }
-            if (!empty($properties->response_editor[$i]) && is_array($properties->response_editor[$i])) {
-                $this->answers[$i]->response = $properties->response_editor[$i]['text'];
-                $this->answers[$i]->responseformat = $properties->response_editor[$i]['format'];
+            if (!empty($properties->response_editor[$i])) {
+                $this->answers[$i]->response = $properties->response_editor[$i];
+                $this->answers[$i]->responseformat = 0;
             }
 
             if (isset($properties->jumpto[$i])) {
@@ -473,12 +473,18 @@ class lesson_add_page_form_matching extends lesson_add_page_form_base {
         for ($i = 2; $i < $this->_customdata['lesson']->maxanswers+2; $i++) {
             $this->_form->addElement('header', 'matchingpair'.($i-1), get_string('matchingpair', 'lesson', $i-1));
             $this->add_answer($i, NULL, ($i < 4));
-            $this->add_response($i, get_string('matchesanswer','lesson'), ($i < 4));
+            $required = ($i < 4);
+            $label = get_string('matchesanswer','lesson');
+            $count = $i;
+            $this->_form->addElement('text', 'response_editor['.$count.']', $label, array('size'=>'50'));
+            $this->_form->setDefault('response_editor['.$count.']', '');
+            if ($required) {
+                $this->_form->addRule('response_editor['.$count.']', get_string('required'), 'required', null, 'client');
+            }
         }
     }
 }
 
-
 class lesson_display_answer_form_matching extends moodleform {
 
     public function definition() {
index c8776de..175e5c6 100644 (file)
@@ -100,7 +100,8 @@ class mod_quiz_overdue_attempt_updater {
 
 
         // SQL to compute timeclose and timelimit for each attempt:
-        $quizausersql = quiz_get_attempt_usertime_sql();
+        $quizausersql = quiz_get_attempt_usertime_sql(
+                "iquiza.state IN ('inprogress', 'overdue') AND iquiza.timecheckstate <= :iprocessto");
 
         // This query should have all the quiz_attempts columns.
         return $DB->get_recordset_sql("
@@ -116,6 +117,6 @@ class mod_quiz_overdue_attempt_updater {
             AND quiza.timecheckstate <= :processto
        ORDER BY quiz.course, quiza.quiz",
 
-                array('processto' => $processto));
+                array('processto' => $processto, 'iprocessto' => $processto));
     }
 }
index 1f108bf..e4414e9 100644 (file)
@@ -454,12 +454,11 @@ if ($quiz_qbanktool) {
 echo '<div class="questionbankwindow ' . $bankclass . 'block">';
 echo '<div class="header"><div class="title"><h2>';
 echo get_string('questionbankcontents', 'quiz') .
-        ' <a href="' . $thispageurl->out(true, array('qbanktool' => '1')) .
-       '" id="showbankcmd">[' . get_string('show').
-       ']</a>
-       <a href="' . $thispageurl->out(true, array('qbanktool' => '0')) .
-       '" id="hidebankcmd">[' . get_string('hide').
-       ']</a>';
+       '&nbsp;[<a href="' . $thispageurl->out(true, array('qbanktool' => '1')) .
+       '" id="showbankcmd">' . get_string('show').
+       '</a><a href="' . $thispageurl->out(true, array('qbanktool' => '0')) .
+       '" id="hidebankcmd">' . get_string('hide').
+       '</a>]';
 echo '</h2></div></div><div class="content">';
 
 echo '<span id="questionbank"></span>';
index ae23dd8..ca78f67 100644 (file)
@@ -783,34 +783,48 @@ function quiz_update_open_attempts(array $conditions) {
     }
 
     $params = array();
-    $coursecond = '';
-    $usercond = '';
-    $quizcond = '';
-    $groupcond = '';
+    $wheres = array("quiza.state IN ('inprogress', 'overdue')");
+    $iwheres = array("iquiza.state IN ('inprogress', 'overdue')");
 
     if (isset($conditions['courseid'])) {
         list ($incond, $inparams) = $DB->get_in_or_equal($conditions['courseid'], SQL_PARAMS_NAMED, 'cid');
         $params = array_merge($params, $inparams);
-        $coursecond = "AND quiza.quiz IN (SELECT q.id FROM {quiz} q WHERE q.course $incond)";
+        $wheres[] = "quiza.quiz IN (SELECT q.id FROM {quiz} q WHERE q.course $incond)";
+        list ($incond, $inparams) = $DB->get_in_or_equal($conditions['courseid'], SQL_PARAMS_NAMED, 'icid');
+        $params = array_merge($params, $inparams);
+        $iwheres[] = "iquiza.quiz IN (SELECT q.id FROM {quiz} q WHERE q.course $incond)";
     }
+
     if (isset($conditions['userid'])) {
         list ($incond, $inparams) = $DB->get_in_or_equal($conditions['userid'], SQL_PARAMS_NAMED, 'uid');
         $params = array_merge($params, $inparams);
-        $usercond = "AND quiza.userid $incond";
+        $wheres[] = "quiza.userid $incond";
+        list ($incond, $inparams) = $DB->get_in_or_equal($conditions['userid'], SQL_PARAMS_NAMED, 'iuid');
+        $params = array_merge($params, $inparams);
+        $iwheres[] = "iquiza.userid $incond";
     }
+
     if (isset($conditions['quizid'])) {
         list ($incond, $inparams) = $DB->get_in_or_equal($conditions['quizid'], SQL_PARAMS_NAMED, 'qid');
         $params = array_merge($params, $inparams);
-        $quizcond = "AND quiza.quiz $incond";
+        $wheres[] = "quiza.quiz $incond";
+        list ($incond, $inparams) = $DB->get_in_or_equal($conditions['quizid'], SQL_PARAMS_NAMED, 'iqid');
+        $params = array_merge($params, $inparams);
+        $iwheres[] = "iquiza.quiz $incond";
     }
+
     if (isset($conditions['groupid'])) {
         list ($incond, $inparams) = $DB->get_in_or_equal($conditions['groupid'], SQL_PARAMS_NAMED, 'gid');
         $params = array_merge($params, $inparams);
-        $groupcond = "AND quiza.quiz IN (SELECT qo.quiz FROM {quiz_overrides} qo WHERE qo.groupid $incond)";
+        $wheres[] = "quiza.quiz IN (SELECT qo.quiz FROM {quiz_overrides} qo WHERE qo.groupid $incond)";
+        list ($incond, $inparams) = $DB->get_in_or_equal($conditions['groupid'], SQL_PARAMS_NAMED, 'igid');
+        $params = array_merge($params, $inparams);
+        $iwheres[] = "iquiza.quiz IN (SELECT qo.quiz FROM {quiz_overrides} qo WHERE qo.groupid $incond)";
     }
 
     // SQL to compute timeclose and timelimit for each attempt:
-    $quizausersql = quiz_get_attempt_usertime_sql();
+    $quizausersql = quiz_get_attempt_usertime_sql(
+            implode("\n                AND ", $iwheres));
 
     // SQL to compute the new timecheckstate
     $timecheckstatesql = "
@@ -822,11 +836,7 @@ function quiz_update_open_attempts(array $conditions) {
           CASE WHEN quiza.state = 'overdue' THEN quiz.graceperiod ELSE 0 END";
 
     // SQL to select which attempts to process
-    $attemptselect = " quiza.state IN ('inprogress', 'overdue')
-                       $coursecond
-                       $usercond
-                       $quizcond
-                       $groupcond";
+    $attemptselect = implode("\n                         AND ", $wheres);
 
    /*
     * Each database handles updates with inner joins differently:
@@ -876,9 +886,14 @@ function quiz_update_open_attempts(array $conditions) {
 /**
  * Returns SQL to compute timeclose and timelimit for every attempt, taking into account user and group overrides.
  *
- * @return string         SQL select with columns attempt.id, usertimeclose, usertimelimit
+ * @param string $redundantwhereclauses extra where clauses to add to the subquery
+ *      for performance. These can use the table alias iquiza for the quiz attempts table.
+ * @return string SQL select with columns attempt.id, usertimeclose, usertimelimit.
  */
-function quiz_get_attempt_usertime_sql() {
+function quiz_get_attempt_usertime_sql($redundantwhereclauses = '') {
+    if ($redundantwhereclauses) {
+        $redundantwhereclauses = 'WHERE ' . $redundantwhereclauses;
+    }
     // The multiple qgo JOINS are necessary because we want timeclose/timelimit = 0 (unlimited) to supercede
     // any other group override
     $quizausersql = "
@@ -894,6 +909,7 @@ function quiz_get_attempt_usertime_sql() {
       LEFT JOIN {quiz_overrides} qgo2 ON qgo2.quiz = iquiza.quiz AND qgo2.groupid = gm.groupid AND qgo2.timeclose > 0
       LEFT JOIN {quiz_overrides} qgo3 ON qgo3.quiz = iquiza.quiz AND qgo3.groupid = gm.groupid AND qgo3.timelimit = 0
       LEFT JOIN {quiz_overrides} qgo4 ON qgo4.quiz = iquiza.quiz AND qgo4.groupid = gm.groupid AND qgo4.timelimit > 0
+          $redundantwhereclauses
        GROUP BY iquiza.id, iquiz.id, iquiz.timeclose, iquiz.timelimit";
     return $quizausersql;
 }
index 23fe7d5..93c1734 100644 (file)
@@ -319,9 +319,14 @@ but in terms of usability, as testing showed,
 http://docs.moodle.org/dev/Quiz_UI_redesign/usability_testing_of_August_2008/Issues#Question_bank_.2F_question_adding_controls_visibility
 it must be ensured that the question
 bank window's title is prominent enough*/
-#page-mod-quiz-edit .questionbankwindow div.header {background-color:#009;color:#fff;background-image:none;padding-top:0.2em;font-weight:bold;}
-#page-mod-quiz-edit .questionbankwindow div.header a{text-decoration:underline;color:#FFF;}
+#page-mod-quiz-edit .questionbankwindow.block div.header {background-color:#009;background-image:none;padding-top:0.2em;font-weight:bold;border:0 none;}
+#page-mod-quiz-edit .questionbankwindow.block div.header div.title h2 {color:#FFF;text-align: center;}
 #page-mod-quiz-edit .collapsed .container{display: none;}
+
+#page-mod-quiz-edit .questionbankwindow a#showbankcmd,
+#page-mod-quiz-edit .questionbankwindow a#hidebankcmd {color: #FFF;text-decoration:underline;}
+#page-mod-quiz-edit .questionbankwindow a#showbankcmd:hover,
+#page-mod-quiz-edit .questionbankwindow a#hidebankcmd:hover {color:#009;background-color:#fff;text-decoration:none;}
 #page-mod-quiz-edit .questionbankwindow #showbankcmd{display:none;}
 #page-mod-quiz-edit .collapsed #showbankcmd{display:inline;}
 #page-mod-quiz-edit .questionbankwindow #hidebankcmd{display:inline;}
index c2f1c40..182de24 100644 (file)
@@ -745,7 +745,7 @@ function scorm_course_format_display($user, $course) {
 }
 
 function scorm_view_display ($user, $scorm, $action, $cm) {
-    global $CFG, $DB, $PAGE, $OUTPUT;
+    global $CFG, $DB, $PAGE, $OUTPUT, $COURSE;
 
     if ($scorm->scormtype != SCORM_TYPE_LOCAL && $scorm->updatefreq == SCORM_UPDATE_EVERYTIME) {
         scorm_parse($scorm, false);
@@ -824,7 +824,7 @@ function scorm_view_display ($user, $scorm, $action, $cm) {
                       <label for="a"><?php print_string('newattempt', 'scorm') ?></label>
             <?php
         }
-        if (!empty($scorm->popup)) {
+        if ($COURSE->format != 'scorm' && !empty($scorm->popup)) {
             echo '<input type="hidden" name="display" value="popup" />'."\n";
         }
         ?>
index 570543d..ecca604 100644 (file)
@@ -135,6 +135,12 @@ $attemptstr = '&amp;attempt=' . $attempt;
 
 $result = scorm_get_toc($USER, $scorm, $cm->id, TOCJSLINK, $currentorg, $scoid, $mode, $attempt, true, true);
 $sco = $result->sco;
+if ($scorm->lastattemptlock == 1 && $result->attemptleft == 0) {
+    echo $OUTPUT->header();
+    echo $OUTPUT->notification(get_string('exceededmaxattempts', 'scorm'));
+    echo $OUTPUT->footer();
+    exit;
+}
 
 if (($mode == 'browse') && ($scorm->hidebrowse == 1)) {
     $mode = 'normal';
@@ -186,7 +192,6 @@ $PAGE->requires->data_for_js('scormplayerdata', Array('cwidth'=>$scorm->width,
                                                       'popupoptions' => $scorm->options), true);
 $PAGE->requires->js('/mod/scorm/request.js', true);
 $PAGE->requires->js('/lib/cookies.js', true);
-$PAGE->requires->css('/mod/scorm/styles.css');
 echo $OUTPUT->header();
 
 // NEW IMS TOC
index 1e65824..f62468b 100644 (file)
             <directory suffix="_test.php">question/engine/tests</directory>
             <directory suffix="_test.php">question/tests</directory>
             <directory suffix="_test.php">question/type/tests</directory>
+            <directory suffix="_test.php">question/engine/upgrade/tests</directory>
+        </testsuite>
+        <testsuite name="quiz_report">
+            <directory suffix="_test.php">mod/quiz/report/tests</directory>
+        </testsuite>
+        <testsuite name="core_rating">
+            <directory suffix="_test.php">rating/tests</directory>
+        </testsuite>
+        <testsuite name="core_repository">
+            <directory suffix="_test.php">repository/tests</directory>
+        </testsuite>
+        <testsuite name="core_user">
+            <directory suffix="_test.php">user/tests</directory>
+        </testsuite>
+        <testsuite name="core_webservice">
+            <directory suffix="_test.php">webservice/tests</directory>
         </testsuite>
 
         <!--Plugin suites: use admin/tool/phpunit/cli/util.php to build phpunit.xml from phpunit.xml.dist with up-to-date list of plugins in current install-->
index 811e9bc..6125015 100644 (file)
@@ -348,18 +348,19 @@ class qformat_default {
         foreach ($questions as $question) {
             if (!empty($question->fraction) and (is_array($question->fraction))) {
                 $fractions = $question->fraction;
-                $answersvalid = true; // in case they are!
+                $invalidfractions = array();
                 foreach ($fractions as $key => $fraction) {
                     $newfraction = match_grade_options($gradeoptionsfull, $fraction,
                             $this->matchgrades);
                     if ($newfraction === false) {
-                        $answersvalid = false;
+                        $invalidfractions[] = $fraction;
                     } else {
                         $fractions[$key] = $newfraction;
                     }
                 }
-                if (!$answersvalid) {
-                    echo $OUTPUT->notification(get_string('invalidgrade', 'question'));
+                if ($invalidfractions) {
+                    echo $OUTPUT->notification(get_string('invalidgrade', 'question',
+                            implode(', ', $invalidfractions)));
                     ++$gradeerrors;
                     continue;
                 } else {
index 6b9edda..744456c 100644 (file)
@@ -87,7 +87,7 @@ class qformat_blackboard_six_qti extends qformat_blackboard_six_base {
                     $this->process_essay($question, $questions);
                     break;
                 default:
-                    $this->error(get_string('unknownorunhandledtype', 'qformat_blackboard_six', $question->qtype));
+                    $this->error(get_string('unknownorunhandledtype', 'question', $question->qtype));
                     break;
             }
         }
index 2f3eccd..bd7db41 100644 (file)
@@ -184,6 +184,7 @@ class qformat_examview extends qformat_based_on_xml {
     }
 
     public function readquestion($qrec) {
+        global $OUTPUT;
 
         $type = trim($qrec['@']['type']);
         $question = $this->defaultquestion();
@@ -224,7 +225,7 @@ class qformat_examview extends qformat_based_on_xml {
                 break;
                 break;
             default:
-                print("<p>Question type ".$type." import not supported for ".$question->questiontext."<p>");
+                echo $OUTPUT->notification(get_string('unknownorunhandledtype', 'question', $type));
                 $question = null;
         }
 
index b4c679a..e3b389d 100644 (file)
@@ -67,6 +67,8 @@ class qformat_learnwise extends qformat_default {
     }
 
     protected function readquestion($lines) {
+        global $OUTPUT;
+
         $text = implode(' ', $lines);
         $text = str_replace(array('\t','\n','\r'), array('','',''), $text);
 
@@ -131,7 +133,7 @@ class qformat_learnwise extends qformat_default {
             }
 
         } else {
-            echo "<p>I don't understand this question type (type = <strong>$type</strong>).</p>\n";
+            echo $OUTPUT->notification(get_string('unknownorunhandledtype', 'question', $type));
         }
 
         $question = $this->defaultquestion();
index d4347bc..0be7ee7 100644 (file)
@@ -70,28 +70,23 @@ class qformat_missingword extends qformat_default {
 
         $answerstart = strpos($text, "{");
         if ($answerstart === false) {
-            if ($this->displayerrors) {
-                echo "<p>$text<p>Could not find a {";
-            }
+            $this->error(get_string('beginanswernotfound', 'qformat_missingword'), $text);
             return false;
         }
 
         $answerfinish = strpos($text, "}");
         if ($answerfinish === false) {
-            if ($this->displayerrors) {
-                echo "<p>$text<p>Could not find a }";
-            }
+            $this->error(get_string('endanswernotfound', 'qformat_missingword'), $text);
             return false;
         }
 
         $answerlength = $answerfinish - $answerstart;
         $answertext = substr($text, $answerstart + 1, $answerlength - 1);
 
-        /// Save the new question text
+        // Save the new question text.
         $question->questiontext = substr_replace($text, "_____", $answerstart, $answerlength+1);
         $question->name = $this->create_default_question_name($question->questiontext, get_string('questionname', 'question'));
 
-
         /// Parse the answers
         $answertext = str_replace("=", "~=", $answertext);
         $answers = explode("~", $answertext);
@@ -105,10 +100,8 @@ class qformat_missingword extends qformat_default {
         $countanswers = count($answers);
 
         switch ($countanswers) {
-            case 0:  // invalid question
-                if ($this->displayerrors) {
-                    echo "<p>No answers found in $answertext";
-                }
+            case 0:  // Invalid question.
+                $this->error(get_string('noanswerfound', 'qformat_missingword'), $answertext);
                 return false;
 
             case 1:
@@ -120,13 +113,16 @@ class qformat_missingword extends qformat_default {
                 }
                 $question->answer[]   = $answer;
                 $question->fraction[] = 1;
-                $question->feedback[] = "";
+                $question->feedback[] = array('text' => '', 'format' => FORMAT_HTML);
 
                 return $question;
 
             default:
                 $question->qtype = MULTICHOICE;
 
+                $question = $this->add_blank_combined_feedback($question);
+                $question->single = 1; // Only one answer allowed.
+
                 foreach ($answers as $key => $answer) {
                     $answer = trim($answer);
 
@@ -166,8 +162,8 @@ class qformat_missingword extends qformat_default {
 #                       $question->fraction[$key] = 0;
                         $question->fraction[$key] = $answeight;
                     }
-                    $question->answer[$key]   = $answer;
-                    $question->feedback[$key] = $comment;
+                    $question->answer[$key]   = array('text' => $answer, 'format' => FORMAT_HTML);
+                    $question->feedback[$key] = array('text' => $comment, 'format' => FORMAT_HTML);
                 }
 
                 return $question;
index 0e190a3..e1fd498 100644 (file)
@@ -26,3 +26,6 @@
 $string['pluginname'] = 'Missing word format';
 $string['pluginname_help'] = 'Missing word format enables questions to be imported via text file.';
 $string['pluginname_link'] = 'Missing word format';
+$string['beginanswernotfound'] = 'Could not find a required "{" character in imported file content.';
+$string['endanswernotfound'] = 'Could not find a required "}" character in imported file content.';
+$string['noanswerfound'] = 'No answers found in question';
diff --git a/question/format/missingword/tests/fixtures/question.missingword1.txt b/question/format/missingword/tests/fixtures/question.missingword1.txt
new file mode 100644 (file)
index 0000000..0580c40
--- /dev/null
@@ -0,0 +1,3 @@
+As soon as we begin to explore our body parts as infants
+we become students of {=anatomy and physiology ~reflexology
+~science ~experiment}, and in a sense we remain students for life.
diff --git a/question/format/missingword/tests/fixtures/question.missingword2.txt b/question/format/missingword/tests/fixtures/question.missingword2.txt
new file mode 100644 (file)
index 0000000..77b58de
--- /dev/null
@@ -0,0 +1,2 @@
+You can use the missing word format to import questions
+into both Moodle's Question bank and {=Lesson} activity.
diff --git a/question/format/missingword/tests/fixtures/question.missingword3.txt b/question/format/missingword/tests/fixtures/question.missingword3.txt
new file mode 100644 (file)
index 0000000..e202f82
--- /dev/null
@@ -0,0 +1,2 @@
+This is {=the best answer#comment on the best answer ~75%a good
+answer#comment on the good answer ~a wrong one#comment on the bad answer}
index 7c929d6..cace8f7 100644 (file)
@@ -137,10 +137,8 @@ class qformat_xhtml extends qformat_default {
         case DESCRIPTION:
             break;
         case MULTIANSWER:
-            $expout .= "<!-- CLOZE type is not supported  -->\n";
-            break;
         default:
-            echo $OUTPUT->notification("No handler for qtype $question->qtype for GIFT export" );
+            $expout .= "<!-- export of $question->qtype type is not supported  -->\n";
         }
         // close off div
         $expout .= "</div>\n\n\n";
index dac965e..10a1346 100644 (file)
@@ -80,6 +80,13 @@ class qtype_essay extends question_type {
         $question->graderinfoformat = $questiondata->options->graderinfoformat;
     }
 
+    public function delete_question($questionid, $contextid) {
+        global $DB;
+
+        $DB->delete_records('qtype_essay_options', array('questionid' => $questionid));
+        parent::delete_question($questionid, $contextid);
+    }
+
     /**
      * @return array the different response formats that the question type supports.
      * internal name => human-readable name.
index 7c82e66..864f356 100644 (file)
@@ -148,7 +148,8 @@ foreach ($modinfo->sections as $sectionnum=>$section) {
             $blogcell = new html_table_cell();
             $blogcell->attributes['class'] = 'blog';
             if ($blogcount = blog_get_associated_count($course->id, $cm->id)) {
-                $blogcell->text = html_writer::link('/blog/index.php?modid='.$cm->id, $blogcount);
+                $blogurl = new moodle_url('/blog/index.php', array('modid' => $cm->id));
+                $blogcell->text = html_writer::link($blogurl, $blogcount);
             } else {
                 $blogcell->text = '-';
             }
index fd30d58..8b8ee4d 100644 (file)
@@ -129,9 +129,19 @@ class profile_field_base {
         global $DB;
 
         $errors = array();
-        /// Check for uniqueness of data if required
-        if ($this->is_unique()) {
-            $value = (is_array($usernew->{$this->inputname}) and isset($usernew->{$this->inputname}['text'])) ? $usernew->{$this->inputname}['text'] : $usernew->{$this->inputname};
+        // Get input value.
+        if (isset($usernew->{$this->inputname})) {
+            if (is_array($usernew->{$this->inputname}) && isset($usernew->{$this->inputname}['text'])) {
+                $value = $usernew->{$this->inputname}['text'];
+            } else {
+                $value = $usernew->{$this->inputname};
+            }
+        } else {
+            $value = '';
+        }
+
+        // Check for uniqueness of data if required.
+        if ($this->is_unique() && (($value !== '') || $this->is_required())) {
             $data = $DB->get_records_sql('
                     SELECT id, userid
                       FROM {user_info_data}
index b53d09a..3a88306 100644 (file)
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062504.01;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062504.03;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.4+ (Build: 20130118)';  // Human-friendly version name
+$release  = '2.3.4+ (Build: 20130125)';  // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level
index abd131c..45d9fd6 100644 (file)
@@ -120,7 +120,7 @@ class webservice_rest_server extends webservice_base_server {
             } else {
                 $response = '<?xml version="1.0" encoding="UTF-8" ?>'."\n";
                 $response .= '<RESPONSE>'."\n";
-                $response .= self::xmlize_result($this->returns, $this->function->returns_desc);
+                $response .= self::xmlize_result($validatedvalues, $this->function->returns_desc);
                 $response .= '</RESPONSE>'."\n";
             }
         }
@@ -248,4 +248,4 @@ class webservice_rest_test_client implements webservice_test_client_interface {
     public function simpletest($serverurl, $function, $params) {
         return download_file_content($serverurl.'&wsfunction='.$function, null, $params);
     }
-}
\ No newline at end of file
+}