Merge branch 'm23_MDL-34374' of git://github.com/danmarsden/moodle into MOODLE_23_STABLE
authorSam Hemelryk <sam@moodle.com>
Sun, 22 Jul 2012 23:38:09 +0000 (11:38 +1200)
committerSam Hemelryk <sam@moodle.com>
Sun, 22 Jul 2012 23:38:09 +0000 (11:38 +1200)
62 files changed:
admin/cli/mysql_collation.php [new file with mode: 0644]
admin/roles/check.php
auth/shibboleth/login.php
blocks/blog_recent/block_blog_recent.php
blocks/navigation/renderer.php
blog/index.php
course/delete.php
course/dndupload.js
course/editsection.php
course/externallib.php
course/format/renderer.php
course/lib.php
course/togglecompletion.php
enrol/authorize/index.php
enrol/database/tests/adodb_test.php
install/lang/ca/install.php
install/lang/is/admin.php
install/lang/is/langconfig.php
install/lang/pt/admin.php
lang/en/error.php
lang/en/role.php
lib/accesslib.php
lib/completion/completion_criteria_completion.php
lib/completion/cron.php
lib/ddl/mysql_sql_generator.php
lib/dml/mysqli_native_moodle_database.php
lib/form/yui/dateselector/assets/skins/sam/dateselector.css
lib/form/yui/dateselector/dateselector.js
lib/formslib.php
lib/javascript-static.js
lib/yui/formchangechecker/formchangechecker.js
mod/assign/adminlib.php
mod/assign/gradingoptionsform.php
mod/assign/gradingtable.php
mod/assign/lang/en/assign.php
mod/assign/lib.php
mod/assign/locallib.php
mod/assign/renderable.php
mod/assign/renderer.php
mod/assign/settings.php
mod/assignment/lib.php
mod/chat/gui_ajax/module.js
mod/choice/renderer.php
mod/data/export.php
mod/forum/lib.php
mod/quiz/module.js
mod/quiz/renderer.php
mod/quiz/report/overview/report.php
mod/quiz/report/statistics/report.php
mod/quiz/version.php
mod/scorm/backup/moodle2/backup_scorm_stepslib.php
mod/scorm/report/interactions/report.php
notes/externallib.php
portfolio/googledocs/lib.php
portfolio/picasa/lib.php
question/type/shortanswer/backup/moodle2/restore_qtype_shortanswer_plugin.class.php
repository/filepicker.js
repository/googledocs/lib.php
repository/picasa/lib.php
theme/base/style/course.css
theme/base/style/filemanager.css
version.php

diff --git a/admin/cli/mysql_collation.php b/admin/cli/mysql_collation.php
new file mode 100644 (file)
index 0000000..9938a3a
--- /dev/null
@@ -0,0 +1,211 @@
+<?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/>.
+
+/**
+ * MySQL collation conversion tool.
+ *
+ * @package    core
+ * @copyright  2012 Petr Skoda (http://skodak.org)
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define('CLI_SCRIPT', true);
+
+require(dirname(dirname(dirname(__FILE__))).'/config.php');
+require_once($CFG->libdir.'/clilib.php');      // cli only functions
+
+if ($DB->get_dbfamily() !== 'mysql') {
+    cli_error('This function is designed for MySQL databases only!');
+}
+
+// now get cli options
+list($options, $unrecognized) = cli_get_params(array('help'=>false, 'list'=>false, 'collation'=>false, 'available'=>false),
+    array('h'=>'help', 'l'=>'list', 'a'=>'available'));
+
+if ($unrecognized) {
+    $unrecognized = implode("\n  ", $unrecognized);
+    cli_error(get_string('cliunknowoption', 'admin', $unrecognized));
+}
+
+$help =
+    "MySQL collation conversions script.
+
+It is strongly recommended to stop the web server before the conversion.
+This script may be executed before the main upgrade - 1.9.x data for example.
+
+Options:
+--collation=COLLATION Convert MySQL tables to different collation
+-l, --list            Show table and column information
+-a, --available       Show list of available collations
+-h, --help            Print out this help
+
+Example:
+\$ sudo -u www-data /usr/bin/php admin/cli/mysql_collation.php --collation=utf8_general_ci
+";
+
+if (!empty($options['collation'])) {
+    $collations = mysql_get_collations();
+    $collation = clean_param($options['collation'], PARAM_ALPHANUMEXT);
+    $collation = strtolower($collation);
+    if (!isset($collations[$collation])) {
+        cli_error("Error: collation '$collation' is not available on this server!");
+    }
+
+    echo "Converting tables and columns to '$collation' for $CFG->wwwroot:\n";
+    $prefix = $DB->get_prefix();
+    $prefix = str_replace('_', '\\_', $prefix);
+    $sql = "SHOW TABLE STATUS WHERE Name LIKE BINARY '$prefix%'";
+    $rs = $DB->get_recordset_sql($sql);
+    $converted = 0;
+    $skipped   = 0;
+    $errors    = 0;
+    foreach ($rs as $table) {
+        echo str_pad($table->name, 40). " - ";
+
+        if ($table->collation === $collation) {
+            echo "NO CHANGE\n";
+            $skipped++;
+
+        } else {
+            $DB->change_database_structure("ALTER TABLE $table->name DEFAULT COLLATE = $collation");
+            echo "CONVERTED\n";
+            $converted++;
+        }
+
+        $sql = "SHOW FULL COLUMNS FROM $table->name WHERE collation IS NOT NULL";
+        $rs2 = $DB->get_recordset_sql($sql);
+        foreach ($rs2 as $column) {
+            $column = (object)array_change_key_case((array)$column, CASE_LOWER);
+            echo '    '.str_pad($column->field, 36). " - ";
+            if ($column->collation === $collation) {
+                echo "NO CHANGE\n";
+                $skipped++;
+                continue;
+            }
+
+            if ($column->type === 'tinytext' or $column->type === 'mediumtext' or $column->type === 'text' or $column->type === 'longtext') {
+                $notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL';
+                $default = (!is_null($column->default) and $column->default !== '') ? "DEFAULT '$column->default'" : '';
+                // primary, unique and inc are not supported for texts
+                $sql = "ALTER TABLE $table->name MODIFY COLUMN $column->field $column->type COLLATE $collation $notnull $default";
+                $DB->change_database_structure($sql);
+
+            } else if (strpos($column->type, 'varchar') === 0) {
+                $notnull = ($column->null === 'NO') ? 'NOT NULL' : 'NULL';
+                $default = !is_null($column->default) ? "DEFAULT '$column->default'" : '';
+                // primary, unique and inc are not supported for texts
+                $sql = "ALTER TABLE $table->name MODIFY COLUMN $column->field $column->type COLLATE $collation $notnull $default";
+                $DB->change_database_structure($sql);
+            } else {
+                echo "ERROR (unknown column type: $column->type)\n";
+                $error++;
+                continue;
+            }
+            echo "CONVERTED\n";
+            $converted++;
+        }
+        $rs2->close();
+    }
+    $rs->close();
+    echo "Converted: $converted, skipped: $skipped, errors: $errors\n";
+    exit(0); // success
+
+} else if (!empty($options['list'])) {
+    echo "List of tables for $CFG->wwwroot:\n";
+    $prefix = $DB->get_prefix();
+    $prefix = str_replace('_', '\\_', $prefix);
+    $sql = "SHOW TABLE STATUS WHERE Name LIKE BINARY '$prefix%'";
+    $rs = $DB->get_recordset_sql($sql);
+    $counts = array();
+    foreach ($rs as $table) {
+        if (isset($counts[$table->collation])) {
+            $counts[$table->collation]++;
+        } else {
+            $counts[$table->collation] = 1;
+        }
+        echo str_pad($table->name, 40);
+        echo $table->collation.  "\n";
+        $collations = mysql_get_column_collations($table->name);
+        foreach ($collations as $columname=>$collation) {
+            if (isset($counts[$collation])) {
+                $counts[$collation]++;
+            } else {
+                $counts[$collation] = 1;
+            }
+            echo '    ';
+            echo str_pad($columname, 36);
+            echo $collation.  "\n";
+        }
+    }
+    $rs->close();
+
+    echo "\n";
+    echo "Table collations summary for $CFG->wwwroot:\n";
+    foreach ($counts as $collation => $count) {
+        echo "$collation: $count\n";
+    }
+    exit(0); // success
+
+} else if (!empty($options['available'])) {
+    echo "List of available MySQL collations for $CFG->wwwroot:\n";
+    $collations = mysql_get_collations();
+    foreach ($collations as $collation) {
+        echo " $collation\n";
+    }
+    die;
+
+} else {
+    echo $help;
+    die;
+}
+
+
+
+// ========== Some functions ==============
+
+function mysql_get_collations() {
+    global $DB;
+
+    $collations = array();
+    $sql = "SHOW COLLATION WHERE Collation LIKE 'utf8\_%' AND Charset = 'utf8'";
+    $rs = $DB->get_recordset_sql($sql);
+    foreach ($rs as $collation) {
+        $collations[$collation->collation] = $collation->collation;
+    }
+    $rs->close();
+
+    $collation = $DB->get_dbcollation();
+    if (isset($collations[$collation])) {
+        $collations[$collation] .= ' (default)';
+    }
+
+    return $collations;
+}
+
+function mysql_get_column_collations($tablename) {
+    global $DB;
+
+    $collations = array();
+    $sql = "SELECT column_name, collation_name
+              FROM INFORMATION_SCHEMA.COLUMNS
+             WHERE table_schema = DATABASE() AND table_name = ? AND collation_name IS NOT NULL";
+    $rs = $DB->get_recordset_sql($sql, array($tablename));
+    foreach($rs as $record) {
+        $collations[$record->column_name] = $record->collation_name;
+    }
+    $rs->close();
+    return $collations;
+}
index 1f6f6ac..470159e 100644 (file)
@@ -104,20 +104,45 @@ switch ($context->contextlevel) {
         break;
 }
 
+// Get the list of the reported-on user's role assignments - must be after
+// the page setup code above, or the language might be wrong.
+$reportuser = $userselector->get_selected_user();
+if (!is_null($reportuser)) {
+    $roleassignments = get_user_roles_with_special($context, $reportuser->id);
+    $rolenames = role_get_names($context);
+}
+
 echo $OUTPUT->header();
-// These are needed early because of tabs.php
-$assignableroles = get_assignable_roles($context, ROLENAME_BOTH);
-$overridableroles = get_overridable_roles($context, ROLENAME_BOTH);
 
 // Print heading.
 echo $OUTPUT->heading($title);
 
 // If a user has been chosen, show all the permissions for this user.
-$reportuser = $userselector->get_selected_user();
 if (!is_null($reportuser)) {
     echo $OUTPUT->box_start('generalbox boxaligncenter boxwidthwide');
-    echo $OUTPUT->heading(get_string('permissionsforuser', 'role', fullname($reportuser)), 3);
 
+    if (!empty($roleassignments)) {
+        echo $OUTPUT->heading(get_string('rolesforuser', 'role', fullname($reportuser)), 3);
+        echo html_writer::start_tag('ul');
+
+        $systemcontext = context_system::instance();
+        foreach ($roleassignments as $ra) {
+            $racontext = context::instance_by_id($ra->contextid);
+            $link = html_writer::link($racontext->get_url(), $racontext->get_context_name());
+
+            $rolename = $rolenames[$ra->roleid]->localname;
+            if (has_capability('moodle/role:manage', $systemcontext)) {
+                $rolename = html_writer::link(new moodle_url('/admin/roles/define.php',
+                        array('action' => 'view', 'roleid' => $ra->roleid)), $rolename);
+            }
+
+            echo html_writer::tag('li', get_string('roleincontext', 'role',
+                    array('role' => $rolename, 'context' => $link)));
+        }
+        echo html_writer::end_tag('ul');
+    }
+
+    echo $OUTPUT->heading(get_string('permissionsforuser', 'role', fullname($reportuser)), 3);
     $table = new check_capability_table($context, $reportuser, $contextname);
     $table->display();
     echo $OUTPUT->box_end();
index ee3372f..6f984c5 100644 (file)
@@ -63,6 +63,7 @@ $PAGE->https_required();
     $loginsite = get_string("loginsite");
 
     $PAGE->set_url('/auth/shibboleth/login.php');
+    $PAGE->set_context(context_system::instance());
     $PAGE->navbar->add($loginsite);
     $PAGE->set_title("$site->fullname: $loginsite");
     $PAGE->set_heading($site->fullname);
index b3d564f..fe6c970 100644 (file)
@@ -86,17 +86,20 @@ class block_blog_recent extends block_base {
 
         $context = $this->page->context;
 
+        $url = new moodle_url('/blog/index.php');
         $filter = array();
         if ($context->contextlevel == CONTEXT_MODULE) {
             $filter['module'] = $context->instanceid;
             $a = new stdClass;
             $a->type = get_string('modulename', $this->page->cm->modname);
             $strview = get_string('viewallmodentries', 'blog', $a);
+            $url->param('modid', $context->instanceid);
         } else if ($context->contextlevel == CONTEXT_COURSE) {
             $filter['course'] = $context->instanceid;
             $a = new stdClass;
             $a->type = get_string('course');
             $strview = get_string('viewblogentries', 'blog', $a);
+            $url->param('courseid', $context->instanceid);
         } else {
             $strview = get_string('viewsiteentries', 'blog');
         }
@@ -104,7 +107,6 @@ class block_blog_recent extends block_base {
 
         $bloglisting = new blog_listing($filter);
         $entries = $bloglisting->get_entries(0, $this->config->numberofrecentblogentries, 4);
-        $url = new moodle_url('/blog/index.php', $filter);
 
         if (!empty($entries)) {
             $entrieslist = array();
index fe91aed..4c3d28c 100644 (file)
@@ -77,6 +77,11 @@ class block_navigation_renderer extends plugin_renderer_base {
             $isexpandable = (empty($expansionlimit) || ($item->type > navigation_node::TYPE_ACTIVITY || $item->type < $expansionlimit) || ($item->contains_active_node() && $item->children->count() > 0));
             $isbranch = $isexpandable && ($item->children->count() > 0 || ($item->has_children() && (isloggedin() || $item->type <= navigation_node::TYPE_CATEGORY)));
 
+            // Skip elements which have no content and no action - no point in showing them
+            if (!$isexpandable && empty($item->action)) {
+                continue;
+            }
+
             $hasicon = ((!$isbranch || $item->type == navigation_node::TYPE_ACTIVITY || $item->type == navigation_node::TYPE_RESOURCE) && $item->icon instanceof renderable);
 
             if ($hasicon) {
index 77476a9..c008427 100644 (file)
@@ -143,7 +143,7 @@ if (!empty($groupid)) {
     }
 
     if (!$course = $DB->get_record('course', array('id'=>$group->courseid))) {
-        print_error(get_string('invalidcourseid', 'blog'));
+        print_error('invalidcourseid');
     }
 
     $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
index ba9c3be..ebe6b78 100644 (file)
     $strcategories = get_string("categories");
 
     if (! $course = $DB->get_record("course", array("id"=>$id))) {
-        print_error("invalidcourseid", 'error', '', $id);
+        print_error("invalidcourseid");
     }
     if ($site->id == $course->id) {
         // can not delete frontpage!
-        print_error("invalidcourseid", 'error', '', $id);
+        print_error("invalidcourseid");
     }
 
     $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
index 4651120..7bfef1d 100644 (file)
@@ -514,7 +514,7 @@ M.course_dndupload = {
             namespan: document.createElement('span')
         };
 
-        preview.li.className = 'dndupload-preview activity resource modtype_resource dndupload-hidden';
+        preview.li.className = 'dndupload-preview dndupload-hidden';
 
         preview.div.className = 'mod-indent';
         preview.li.appendChild(preview.div);
index ecd905b..e4d6bea 100644 (file)
@@ -33,9 +33,9 @@ require_once($CFG->libdir . '/conditionlib.php');
 require_once('editsection_form.php');
 
 $id = required_param('id',PARAM_INT);    // Week/topic ID
-$sectionreturn = optional_param('sectionreturn', 0, PARAM_BOOL);
+$sectionreturn = optional_param('sr', 0, PARAM_INT);
 
-$PAGE->set_url('/course/editsection.php', array('id'=>$id, 'sectionreturn'=> $sectionreturn));
+$PAGE->set_url('/course/editsection.php', array('id'=>$id, 'sr'=> $sectionreturn));
 
 $section = $DB->get_record('course_sections', array('id' => $id), '*', MUST_EXIST);
 $course = $DB->get_record('course', array('id' => $section->course), '*', MUST_EXIST);
@@ -60,11 +60,7 @@ $mform = new editsection_form($PAGE->url, array('course' => $course, 'editoropti
         'cs' => $section, 'showavailability' => $section->showavailability));
 $mform->set_data($section); // set current value
 
-if ($sectionreturn) {
-    $returnurl = course_get_url($course, $section->section);
-} else {
-    $returnurl = course_get_url($course);
-}
+$returnurl = course_get_url($course, $sectionreturn);
 
 /// If data submitted, then process and store.
 if ($mform->is_cancelled()){
index 41c5ab4..b18c0a4 100644 (file)
@@ -668,13 +668,12 @@ class core_course_external extends external_api {
                 'options' => new external_multiple_structure(
                     new external_single_structure(
                         array(
-                                'name' => new external_value(PARAM_ALPHA, 'The backup option name:
+                                'name' => new external_value(PARAM_ALPHAEXT, 'The backup option name:
                                             "activities" (int) Include course activites (default to 1 that is equal to yes),
                                             "blocks" (int) Include course blocks (default to 1 that is equal to yes),
                                             "filters" (int) Include course filters  (default to 1 that is equal to yes),
                                             "users" (int) Include users (default to 0 that is equal to no),
                                             "role_assignments" (int) Include role assignments  (default to 0 that is equal to no),
-                                            "user_files" (int) Include user files  (default to 0 that is equal to no),
                                             "comments" (int) Include user comments  (default to 0 that is equal to no),
                                             "completion_information" (int) Include user course completion information  (default to 0 that is equal to no),
                                             "logs" (int) Include course logs  (default to 0 that is equal to no),
@@ -722,7 +721,7 @@ class core_course_external extends external_api {
         // Context validation.
 
         if (! ($course = $DB->get_record('course', array('id'=>$params['courseid'])))) {
-            throw new moodle_exception('invalidcourseid', 'error', '', $params['courseid']);
+            throw new moodle_exception('invalidcourseid', 'error');
         }
 
         // Category where duplicated course is going to be created.
@@ -739,7 +738,6 @@ class core_course_external extends external_api {
             'filters' => 1,
             'users' => 0,
             'role_assignments' => 0,
-            'user_files' => 0,
             'comments' => 0,
             'completion_information' => 0,
             'logs' => 0,
index b7c0e21..1309025 100644 (file)
@@ -122,9 +122,10 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
      * @param stdClass $section The course_section entry from DB
      * @param stdClass $course The course entry from DB
      * @param bool $onsectionpage true if being printed on a single-section page
+     * @param int $sectionreturn The section to return to after an action
      * @return string HTML to output.
      */
-    protected function section_header($section, $course, $onsectionpage) {
+    protected function section_header($section, $course, $onsectionpage, $sectionreturn=0) {
         global $PAGE;
 
         $o = '';
@@ -150,7 +151,13 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         $o.= html_writer::tag('div', $rightcontent, array('class' => 'right side'));
         $o.= html_writer::start_tag('div', array('class' => 'content'));
 
-        if (!$onsectionpage) {
+        // When not on a section page, we display the section titles except the general section if null
+        $hasnamenotsecpg = (!$onsectionpage && ($section->section != 0 || !is_null($section->name)));
+
+        // When on a section page, we only display the general section title, if title is not the default one
+        $hasnamesecpg = ($onsectionpage && ($section->section == 0 && !is_null($section->name)));
+
+        if ($hasnamenotsecpg || $hasnamesecpg) {
             $o.= $this->output->heading($this->section_title($section, $course), 3, 'sectionname');
         }
 
@@ -159,12 +166,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
 
         $context = context_course::instance($course->id);
         if ($PAGE->user_is_editing() && has_capability('moodle/course:update', $context)) {
-            $url = new moodle_url('/course/editsection.php', array('id'=>$section->id));
-
-            if ($onsectionpage) {
-                $url->param('sectionreturn', 1);
-            }
-
+            $url = new moodle_url('/course/editsection.php', array('id'=>$section->id, 'sr'=>$sectionreturn));
             $o.= html_writer::link($url,
                 html_writer::empty_tag('img', array('src' => $this->output->pix_url('t/edit'), 'class' => 'iconsmall edit')),
                 array('title' => get_string('editsummary')));
@@ -560,10 +562,10 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         $thissection = $sections[0];
         if ($thissection->summary or $thissection->sequence or $PAGE->user_is_editing()) {
             echo $this->start_section_list();
-            echo $this->section_header($thissection, $course, true);
-            print_section($course, $thissection, $mods, $modnamesused, true);
+            echo $this->section_header($thissection, $course, true, $displaysection);
+            print_section($course, $thissection, $mods, $modnamesused, true, "100%", false, $displaysection);
             if ($PAGE->user_is_editing()) {
-                print_section_add_menus($course, 0, $modnames, false, false, true);
+                print_section_add_menus($course, 0, $modnames, false, false, $displaysection);
             }
             echo $this->section_footer();
             echo $this->end_section_list();
@@ -592,14 +594,14 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
 
         // The requested section page.
         $thissection = $sections[$displaysection];
-        echo $this->section_header($thissection, $course, true);
+        echo $this->section_header($thissection, $course, true, $displaysection);
         // Show completion help icon.
         $completioninfo = new completion_info($course);
         echo $completioninfo->display_help_icon();
 
-        print_section($course, $thissection, $mods, $modnamesused, true, '100%', false, true);
+        print_section($course, $thissection, $mods, $modnamesused, true, '100%', false, $displaysection);
         if ($PAGE->user_is_editing()) {
-            print_section_add_menus($course, $displaysection, $modnames, false, false, true);
+            print_section_add_menus($course, $displaysection, $modnames, false, false, $displaysection);
         }
         echo $this->section_footer();
         echo $this->end_section_list();
@@ -646,7 +648,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
         $thissection = $sections[0];
         unset($sections[0]);
         if ($thissection->summary or $thissection->sequence or $PAGE->user_is_editing()) {
-            echo $this->section_header($thissection, $course, true);
+            echo $this->section_header($thissection, $course, false);
             print_section($course, $thissection, $mods, $modnamesused, true);
             if ($PAGE->user_is_editing()) {
                 print_section_add_menus($course, 0, $modnames);
index 374b309..63df417 100644 (file)
@@ -1376,8 +1376,18 @@ function get_print_section_cm_text(cm_info $cm, $course) {
 
 /**
  * Prints a section full of activity modules
+ *
+ * @param stdClass $course The course
+ * @param stdClass $section The section
+ * @param array $mods The modules in the section
+ * @param array $modnamesused An array containing the list of modules and their names
+ * @param bool $absolute All links are absolute
+ * @param string $width Width of the container
+ * @param bool $hidecompletion Hide completion status
+ * @param int $sectionreturn The section to return to
+ * @return void
  */
-function print_section($course, $section, $mods, $modnamesused, $absolute=false, $width="100%", $hidecompletion=false, $sectionreturn = false) {
+function print_section($course, $section, $mods, $modnamesused, $absolute=false, $width="100%", $hidecompletion=false, $sectionreturn=0) {
     global $CFG, $USER, $DB, $PAGE, $OUTPUT;
 
     static $initialised;
@@ -1637,12 +1647,7 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                     $mod->groupmode = false;
                 }
                 echo '&nbsp;&nbsp;';
-
-                if ($sectionreturn) {
-                    echo make_editing_buttons($mod, $absolute, true, $mod->indent, $section->section);
-                } else {
-                    echo make_editing_buttons($mod, $absolute, true, $mod->indent, 0);
-                }
+                echo make_editing_buttons($mod, $absolute, true, $mod->indent, $sectionreturn);
                 echo $mod->get_after_edit_icons();
             }
 
@@ -1761,8 +1766,16 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
 
 /**
  * Prints the menus to add activities and resources.
+ *
+ * @param stdClass $course The course
+ * @param stdClass $section The section
+ * @param array $modnames An array containing the list of modules and their names
+ * @param bool $vertical Vertical orientation
+ * @param bool $return Return the menus or send them to output
+ * @param int $sectionreturn The section to link back to
+ * @return void|string depending on $return
  */
-function print_section_add_menus($course, $section, $modnames, $vertical=false, $return=false, $sectionreturn = false) {
+function print_section_add_menus($course, $section, $modnames, $vertical=false, $return=false, $sectionreturn=0) {
     global $CFG, $OUTPUT;
 
     // check to see if user can add menus
@@ -1778,14 +1791,7 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false,
     $activities = array();
 
     // We need to add the section section to the link for each module
-    $sectionlink = '&section=' . $section;
-
-    // We need to add the section to return to
-    if ($sectionreturn) {
-        $sectionreturnlink = '&sr=' . $section;
-    } else {
-        $sectionreturnlink = '&sr=0';
-    }
+    $sectionlink = '&section=' . $section . '&sr=' . $sectionreturn;
 
     foreach ($modules as $module) {
         if (isset($module->types)) {
@@ -1793,7 +1799,7 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false,
             // NOTE: this is legacy stuff, module subtypes are very strongly discouraged!!
             $subtypes = array();
             foreach ($module->types as $subtype) {
-                $subtypes[$subtype->link . $sectionlink . $sectionreturnlink] = $subtype->title;
+                $subtypes[$subtype->link . $sectionlink] = $subtype->title;
             }
 
             // Sort module subtypes into the list
@@ -1815,11 +1821,11 @@ function print_section_add_menus($course, $section, $modnames, $vertical=false,
         } else {
             // This module has no subtypes
             if ($module->archetype == MOD_ARCHETYPE_RESOURCE) {
-                $resources[$module->link . $sectionlink . $sectionreturnlink] = $module->title;
+                $resources[$module->link . $sectionlink] = $module->title;
             } else if ($module->archetype === MOD_ARCHETYPE_SYSTEM) {
                 // System modules cannot be added by user, do not add to dropdown
             } else {
-                $activities[$module->link . $sectionlink . $sectionreturnlink] = $module->title;
+                $activities[$module->link . $sectionlink] = $module->title;
             }
         }
     }
@@ -4033,7 +4039,7 @@ function average_number_of_participants() {
         WHERE ue.enrolid = e.id
             AND e.courseid <> :siteid
             AND c.id = e.courseid
-            AND c.visible = 1) as total';
+            AND c.visible = 1)';
     $params = array('siteid' => $SITE->id);
     $enrolmenttotal = $DB->count_records_sql($sql, $params);
 
@@ -4066,7 +4072,7 @@ function average_number_of_courses_modules() {
         WHERE c.id = cm.course
             AND c.id <> :siteid
             AND cm.visible = 1
-            AND c.visible = 1) as total';
+            AND c.visible = 1)';
     $params = array('siteid' => $SITE->id);
     $moduletotal = $DB->count_records_sql($sql, $params);
 
index d720144..19a584b 100644 (file)
@@ -53,7 +53,7 @@ if ($courseid) {
     if ($user && $rolec) {
         require_sesskey();
 
-        completion_criteria::factory((object) array('id'=>$rolec, 'criteriatype'=>COMPLETION_CRITERIA_TYPE_ROLE)); //TODO: this is dumb, because it does not fetch the data?!?!
+        completion_criteria::factory(array('id'=>$rolec, 'criteriatype'=>COMPLETION_CRITERIA_TYPE_ROLE)); //TODO: this is dumb, because it does not fetch the data?!?!
         $criteria = completion_criteria_role::fetch(array('id'=>$rolec));
 
         if ($criteria and user_has_role_assignment($USER->id, $criteria->role, $context->id)) {
index 5bdee18..7b93b04 100644 (file)
@@ -53,7 +53,7 @@
 
 /// Get course
     if (!($course = $DB->get_record('course', array('id'=>$courseid)))) {
-        print_error('invalidcourseid', '', '', $courseid);
+        print_error('invalidcourseid');
     }
 
 /// Only SITE users can access to this page
index 2336d53..7f30c07 100644 (file)
@@ -70,7 +70,11 @@ class core_adodb_testcase extends advanced_testcase {
                 set_config('dbsetupsql', 'SET NAMES \'UTF-8\'', 'enrol_database');
                 set_config('dbsybasequoting', '0', 'enrol_database');
                 if (!empty($CFG->dboptions['dbsocket']) and ($CFG->dbhost === 'localhost' or $CFG->dbhost === '127.0.0.1')) {
-                    set_config('dbhost', $CFG->dboptions['dbsocket'], 'enrol_database');
+                    if (strpos($CFG->dboptions['dbsocket'], '/') !== false) {
+                      set_config('dbhost', $CFG->dboptions['dbsocket'], 'enrol_database');
+                    } else {
+                      set_config('dbhost', '', 'enrol_database');
+                    }
                 }
                 break;
 
index 940d880..fb62037 100644 (file)
@@ -70,6 +70,11 @@ $string['pathsroparentdataroot'] = 'No es pot escriure en el directori pare ({$a
 $string['pathssubadmindir'] = 'Alguns serveis d\'allotjament web (pocs) utilitzen un URL especial /admin p. ex. per a accedir a un tauler de control o quelcom semblant. Malauradament això entra en conflicte amb la ubicació estàndard de les pàgines d\'administració de Moodle. Podeu arreglar aquest problema canviant el nom del directori d\'administració de Moodle en la vostra instal·lació i posant el nou nom aquí. Per exemple <em>moodleadmin</em>. Això modificarà els enllaços d\'administració de Moodle.';
 $string['pathssubdataroot'] = 'Necessiteu un espai on Moodle pugui desar els fitxers penjats. Aquest directori hauria de tenir permisos de lectura I ESCRIPTURA per a l\'usuari del servidor web (normalment \'nobody\' o \'apache\'), però no cal que sigui accessible directament via web. L\'instal·lador provarà de crear-lo si no existeix.';
 $string['pathssubdirroot'] = 'Camí complet del directori d\'instal·lació de Moodle.';
+$string['pathssubwwwroot'] = 'L\'adreça web completa on s\'accedirà a Moodle.
+No és possible accedir a Moodle en diferents adreces.
+Si el vostre lloc té múltiples adreces públiques haureu de configurar redireccions permanents per a totes excepte aquesta.
+Si el vostre lloc és accessible tant des d\'Internet com des d\'una intranet, utilitzeu aquí l\'adreça pública i configureu el DNS de manera que els usuaris de la intranet puguin utilitzar també l\'adreça pública.
+Si l\'adreça no és correcta, canvieu l\'URL en el vostre navegador per reiniciar la instal·lació amb un altre valor.';
 $string['pathsunsecuredataroot'] = 'La ubicació del dataroot no és segura.';
 $string['pathswrongadmindir'] = 'No existeix el directori d\'administració';
 $string['phpextension'] = 'Extensió PHP {$a}';
index 1b5f34a..9bae23d 100644 (file)
@@ -32,6 +32,7 @@ defined('MOODLE_INTERNAL') || die();
 
 $string['clianswerno'] = 'n';
 $string['cliansweryes'] = 'j';
+$string['cliincorrectvalueerror'] = 'Villa, ótækt gildi "{$a->value}" fyrir "{$a->option}"';
 $string['cliincorrectvalueretry'] = 'Rangt gildi, vinsamlegast reyndu aftur';
 $string['clitypevalue'] = 'Sláðu inn gildi';
 $string['clitypevaluedefault'] = 'Sláðu inn gildi, sláðu á Enter hnappinn á lyklaborðinu til að nota sjálfgefið gildi ({$a})';
index 4de4bef..bcf067a 100644 (file)
@@ -31,4 +31,4 @@
 defined('MOODLE_INTERNAL') || die();
 
 $string['thisdirection'] = 'ltr';
-$string['thislanguage'] = '&Iacute;slenska';
+$string['thislanguage'] = 'Íslenska';
index 09bd68f..beeead1 100644 (file)
@@ -32,11 +32,13 @@ defined('MOODLE_INTERNAL') || die();
 
 $string['clianswerno'] = 'n';
 $string['cliansweryes'] = 's';
-$string['cliincorrectvalueerror'] = 'Erro: o valor "{$a->value}" não é permitido para a opção "{$a->option}"';
+$string['cliincorrectvalueerror'] = 'Erro. Valor "{$a->value}" incorreto para "{$a->option}"';
 $string['cliincorrectvalueretry'] = 'Valor incorreto, por favor tente novamente';
 $string['clitypevalue'] = 'valor do tipo';
 $string['clitypevaluedefault'] = 'valor do tipo, pressione a tecla Enter para usar o valor predefinido ({$a})';
-$string['cliunknowoption'] = 'Opções desconhecidas: {$a} Por favor use a opção --help';
+$string['cliunknowoption'] = 'Opções desconhecidas:
+{$a}
+Por favor use a opção --help';
 $string['cliyesnoprompt'] = 'digite s (para sim) ou n (para não)';
 $string['environmentrequireinstall'] = 'deve estar instalada e ativa';
 $string['environmentrequireversion'] = 'é requerida a versão {$a->needed} e está a correr a versão {$a->current}';
index b40859b..7ad032c 100644 (file)
@@ -280,7 +280,7 @@ $string['invalidcomponent'] = 'Invalid component name';
 $string['invalidconfirmdata'] = 'Invalid confirmation data';
 $string['invalidcontext'] = 'Invalid context';
 $string['invalidcourse'] = 'Invalid course';
-$string['invalidcourseid'] = 'You are trying to use an invalid course ID: ({$a})';
+$string['invalidcourseid'] = 'You are trying to use an invalid course ID';
 $string['invalidcourselevel'] = 'Incorrect context level';
 $string['invalidcoursemodule'] = 'Invalid course module ID';
 $string['invalidcoursenameshort'] = 'Invalid short course name';
index a8058ad..ffbdec3 100644 (file)
@@ -301,6 +301,7 @@ $string['role:assign'] = 'Assign roles to users';
 $string['roleassignments'] = 'Role assignments';
 $string['roledefinitions'] = 'Role definitions';
 $string['rolefullname'] = 'Role name';
+$string['roleincontext'] = '{$a->role} in {$a->context}';
 $string['role:manage'] = 'Create and manage roles';
 $string['role:override'] = 'Override permissions for others';
 $string['role:review'] = 'Review permissions for others';
@@ -311,6 +312,7 @@ $string['roles_help'] = 'A role is a collection of permissions defined for the w
 $string['roles_link'] = 'roles';
 $string['role:safeoverride'] = 'Override safe permissions for others';
 $string['roleselect'] = 'Select role';
+$string['rolesforuser'] = 'Roles for user {$a}';
 $string['roleshortname'] = 'Short name';
 $string['role:switchroles'] = 'Switch to other roles';
 $string['roletoassign'] = 'Role to assign';
index de180b4..b8aa9f9 100644 (file)
@@ -3020,6 +3020,53 @@ function get_user_roles(context $context, $userid = 0, $checkparentcontexts = tr
     return $DB->get_records_sql($sql ,$params);
 }
 
+/**
+ * Like get_user_roles, but adds in the authenticated user role, and the front
+ * page roles, if applicable.
+ *
+ * @param context $context the context.
+ * @param int $userid optional. Defaults to $USER->id
+ * @return array of objects with fields ->userid, ->contextid and ->roleid.
+ */
+function get_user_roles_with_special(context $context, $userid = 0) {
+    global $CFG, $USER;
+
+    if (empty($userid)) {
+        if (empty($USER->id)) {
+            return array();
+        }
+        $userid = $USER->id;
+    }
+
+    $ras = get_user_roles($context, $userid);
+
+    // Add front-page role if relevant.
+    $defaultfrontpageroleid = isset($CFG->defaultfrontpageroleid) ? $CFG->defaultfrontpageroleid : 0;
+    $isfrontpage = ($context->contextlevel == CONTEXT_COURSE && $context->instanceid == SITEID) ||
+            is_inside_frontpage($context);
+    if ($defaultfrontpageroleid && $isfrontpage) {
+        $frontpagecontext = context_course::instance(SITEID);
+        $ra = new stdClass();
+        $ra->userid = $userid;
+        $ra->contextid = $frontpagecontext->id;
+        $ra->roleid = $defaultfrontpageroleid;
+        $ras[] = $ra;
+    }
+
+    // Add authenticated user role if relevant.
+    $defaultuserroleid      = isset($CFG->defaultuserroleid) ? $CFG->defaultuserroleid : 0;
+    if ($defaultuserroleid && !isguestuser($userid)) {
+        $systemcontext = context_system::instance();
+        $ra = new stdClass();
+        $ra->userid = $userid;
+        $ra->contextid = $systemcontext->id;
+        $ra->roleid = $defaultuserroleid;
+        $ras[] = $ra;
+    }
+
+    return $ras;
+}
+
 /**
  * Creates a record in the role_allow_override table
  *
@@ -4136,6 +4183,15 @@ function role_get_name($role, context_course $coursecontext) {
     }
 }
 
+/**
+ * Get all the localised role names for a context.
+ * @param context $context the context
+ * @param array of role objects with a ->localname field containing the context-specific role name.
+ */
+function role_get_names(context $context) {
+    return role_fix_names(get_all_roles(), $context);
+}
+
 /**
  * Prepare list of roles for display, apply aliases and format text
  *
index 7f44800..dabe552 100644 (file)
@@ -153,7 +153,7 @@ class completion_criteria_completion extends data_object {
 
             $record = $DB->get_record('course_completion_criteria', $params);
 
-            $this->attach_criteria(completion_criteria::factory($record));
+            $this->attach_criteria(completion_criteria::factory((array) $record));
         }
 
         return $this->_criteria;
index 3645c06..bf2a646 100644 (file)
@@ -377,10 +377,11 @@ function completion_cron_completions() {
         SET
             reaggregate = 0
         WHERE
-            reaggregate < {$timestarted}
+            reaggregate < :timestarted
+        AND reaggregate > 0
     ";
 
-    $DB->execute($sql);
+    $DB->execute($sql, array('timestarted' => $timestarted));
 }
 
 /**
index 6ae310f..bbd6de2 100644 (file)
@@ -117,23 +117,25 @@ class mysql_sql_generator extends sql_generator {
      * by any of its comments, indexes and sequence creation SQL statements.
      */
     public function getCreateTableSQL($xmldb_table) {
-        // first find out if want some special db engine
-        $engine = null;
-        if (method_exists($this->mdb, 'get_dbengine')) {
-            $engine = $this->mdb->get_dbengine();
-        }
+        // First find out if want some special db engine.
+        $engine = $this->mdb->get_dbengine();
+        // Do we know collation?
+        $collation = $this->mdb->get_dbcollation();
 
         $sqlarr = parent::getCreateTableSQL($xmldb_table);
 
-        if (!$engine) {
-            // we rely on database defaults
-            return $sqlarr;
-        }
-
-        // let's inject the engine into SQL
+        // Let's inject the extra MySQL tweaks.
         foreach ($sqlarr as $i=>$sql) {
             if (strpos($sql, 'CREATE TABLE ') === 0) {
-                $sqlarr[$i] .= " ENGINE = $engine";
+                if ($engine) {
+                    $sqlarr[$i] .= " ENGINE = $engine";
+                }
+                if ($collation) {
+                    if (strpos($collation, 'utf8_') === 0) {
+                        $sqlarr[$i] .= " DEFAULT CHARACTER SET utf8";
+                    }
+                    $sqlarr[$i] .= " DEFAULT COLLATE = $collation";
+                }
             }
         }
 
@@ -148,9 +150,26 @@ class mysql_sql_generator extends sql_generator {
      * @return array of sql statements
      */
     public function getCreateTempTableSQL($xmldb_table) {
+        // Do we know collation?
+        $collation = $this->mdb->get_dbcollation();
         $this->temptables->add_temptable($xmldb_table->getName());
-        $sqlarr = parent::getCreateTableSQL($xmldb_table); // we do not want the engine hack included in create table SQL
-        $sqlarr = preg_replace('/^CREATE TABLE (.*)/s', 'CREATE TEMPORARY TABLE $1', $sqlarr);
+
+        $sqlarr = parent::getCreateTableSQL($xmldb_table);
+
+        // Let's inject the extra MySQL tweaks.
+        foreach ($sqlarr as $i=>$sql) {
+            if (strpos($sql, 'CREATE TABLE ') === 0) {
+                // We do not want the engine hack included in create table SQL.
+                $sqlarr[$i] = preg_replace('/^CREATE TABLE (.*)/s', 'CREATE TEMPORARY TABLE $1', $sql);
+                if ($collation) {
+                    if (strpos($collation, 'utf8_') === 0) {
+                        $sqlarr[$i] .= " DEFAULT CHARACTER SET utf8";
+                    }
+                    $sqlarr[$i] .= " DEFAULT COLLATE $collation";
+                }
+            }
+        }
+
         return $sqlarr;
     }
 
@@ -231,9 +250,21 @@ class mysql_sql_generator extends sql_generator {
                     $xmldb_length='255';
                 }
                 $dbtype .= '(' . $xmldb_length . ')';
+                if ($collation = $this->mdb->get_dbcollation()) {
+                    if (strpos($collation, 'utf8_') === 0) {
+                        $dbtype .= " CHARACTER SET utf8";
+                    }
+                    $dbtype .= " COLLATE $collation";
+                }
                 break;
             case XMLDB_TYPE_TEXT:
                 $dbtype = 'LONGTEXT';
+                if ($collation = $this->mdb->get_dbcollation()) {
+                    if (strpos($collation, 'utf8_') === 0) {
+                        $dbtype .= " CHARACTER SET utf8";
+                    }
+                    $dbtype .= " COLLATE $collation";
+                }
                 break;
             case XMLDB_TYPE_BINARY:
                 $dbtype = 'LONGBLOB';
@@ -333,18 +364,14 @@ class mysql_sql_generator extends sql_generator {
      */
     public function isNameInUse($object_name, $type, $table_name) {
 
-        // Calculate the real table name
-        $xmldb_table = new xmldb_table($table_name);
-        $tname = $this->getTableName($xmldb_table);
-
         switch($type) {
             case 'ix':
             case 'uix':
                 // First of all, check table exists
                 $metatables = $this->mdb->get_tables();
-                if (isset($metatables[$tname])) {
+                if (isset($metatables[$table_name])) {
                     // Fetch all the indexes in the table
-                    if ($indexes = $this->mdb->get_indexes($tname)) {
+                    if ($indexes = $this->mdb->get_indexes($table_name)) {
                         // Look for existing index in array
                         if (isset($indexes[$object_name])) {
                             return true;
index 93311bd..9294c07 100644 (file)
@@ -82,7 +82,13 @@ class mysqli_native_moodle_database extends moodle_database {
             throw new dml_connection_exception($dberr);
         }
 
-        $result = $conn->query("CREATE DATABASE $dbname DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci");
+        if (isset($dboptions['dbcollation']) and strpos($dboptions['dbcollation'], 'utf8_') === 0) {
+            $collation = $dboptions['dbcollation'];
+        } else {
+            $collation = 'utf8_unicode_ci';
+        }
+
+        $result = $conn->query("CREATE DATABASE $dbname DEFAULT CHARACTER SET utf8 DEFAULT COLLATE ".$collation);
 
         $conn->close();
 
@@ -146,22 +152,28 @@ class mysqli_native_moodle_database extends moodle_database {
             return $this->dboptions['dbengine'];
         }
 
+        if ($this->external) {
+            return null;
+        }
+
         $engine = null;
 
-        if (!$this->external) {
-            // look for current engine of our config table (the first table that gets created),
-            // so that we create all tables with the same engine
-            $sql = "SELECT engine FROM INFORMATION_SCHEMA.TABLES WHERE table_schema = DATABASE() AND table_name = '{$this->prefix}config'";
-            $this->query_start($sql, NULL, SQL_QUERY_AUX);
-            $result = $this->mysqli->query($sql);
-            $this->query_end($result);
-            if ($rec = $result->fetch_assoc()) {
-                $engine = $rec['engine'];
-            }
-            $result->close();
+        // Look for current engine of our config table (the first table that gets created),
+        // so that we create all tables with the same engine.
+        $sql = "SELECT engine
+                  FROM INFORMATION_SCHEMA.TABLES
+                 WHERE table_schema = DATABASE() AND table_name = '{$this->prefix}config'";
+        $this->query_start($sql, NULL, SQL_QUERY_AUX);
+        $result = $this->mysqli->query($sql);
+        $this->query_end($result);
+        if ($rec = $result->fetch_assoc()) {
+            $engine = $rec['engine'];
         }
+        $result->close();
 
         if ($engine) {
+            // Cache the result to improve performance.
+            $this->dboptions['dbengine'] = $engine;
             return $engine;
         }
 
@@ -175,7 +187,7 @@ class mysqli_native_moodle_database extends moodle_database {
         }
         $result->close();
 
-        if (!$this->external and $engine === 'MyISAM') {
+        if ($engine === 'MyISAM') {
             // we really do not want MyISAM for Moodle, InnoDB or XtraDB is a reasonable defaults if supported
             $sql = "SHOW STORAGE ENGINES";
             $this->query_start($sql, NULL, SQL_QUERY_AUX);
@@ -196,9 +208,77 @@ class mysqli_native_moodle_database extends moodle_database {
             }
         }
 
+        // Cache the result to improve performance.
+        $this->dboptions['dbengine'] = $engine;
         return $engine;
     }
 
+    /**
+     * Returns the current MySQL db collation.
+     *
+     * This is an ugly workaround for MySQL default collation problems.
+     *
+     * @return string or null MySQL collation name
+     */
+    public function get_dbcollation() {
+        if (isset($this->dboptions['dbcollation'])) {
+            return $this->dboptions['dbcollation'];
+        }
+        if ($this->external) {
+            return null;
+        }
+
+        $collation = null;
+
+        // Look for current collation of our config table (the first table that gets created),
+        // so that we create all tables with the same collation.
+        $sql = "SELECT collation_name
+                  FROM INFORMATION_SCHEMA.COLUMNS
+                 WHERE table_schema = DATABASE() AND table_name = '{$this->prefix}config' AND column_name = 'value'";
+        $this->query_start($sql, NULL, SQL_QUERY_AUX);
+        $result = $this->mysqli->query($sql);
+        $this->query_end($result);
+        if ($rec = $result->fetch_assoc()) {
+            $collation = $rec['collation_name'];
+        }
+        $result->close();
+
+        if (!$collation) {
+            // Get the default database collation, but only if using UTF-8.
+            $sql = "SELECT @@collation_database";
+            $this->query_start($sql, NULL, SQL_QUERY_AUX);
+            $result = $this->mysqli->query($sql);
+            $this->query_end($result);
+            if ($rec = $result->fetch_assoc()) {
+                if (strpos($rec['@@collation_database'], 'utf8_') === 0) {
+                    $collation = $rec['@@collation_database'];
+                }
+            }
+            $result->close();
+        }
+
+        if (!$collation) {
+            // We want only utf8 compatible collations.
+            $collation = null;
+            $sql = "SHOW COLLATION WHERE Collation LIKE 'utf8\_%' AND Charset = 'utf8'";
+            $this->query_start($sql, NULL, SQL_QUERY_AUX);
+            $result = $this->mysqli->query($sql);
+            $this->query_end($result);
+            while ($res = $result->fetch_assoc()) {
+                $collation = $res['Collation'];
+                if (strtoupper($res['Default']) === 'YES') {
+                    $collation = $res['Collation'];
+                    break;
+                }
+            }
+            $result->close();
+        }
+
+        // Cache the result to improve performance.
+        $this->dboptions['dbcollation'] = $collation;
+        return $collation;
+    }
+
     /**
      * Returns localised database type name
      * Note: can be used before connect()
index 01a37e7..d8abda4 100644 (file)
@@ -1,3 +1,4 @@
 #dateselector-calendar-panel {background-color:#999;border-bottom:3px solid #999;border-right:3px solid #999;}
 #dateselector-calendar-content {border:1px solid #666;margin-top:-3px;margin-left:-3px;}
+#dateselector-calendar-content_t th.calweekdaycell {padding-left:3px; padding-right:3px;}
 body.ie #dateselector-calendar-panel.yui3-overlay-hidden table {display:none;}
\ No newline at end of file
index d403547..1109b22 100644 (file)
@@ -197,7 +197,30 @@ YUI.add('moodle-form-dateselector', function(Y) {
             this.calendar = new YAHOO.widget.Calendar(document.getElementById('dateselector-calendar-content'), {
                 iframe: false,
                 hide_blank_weeks: true,
-                start_weekday: config.firstdayofweek
+                start_weekday: config.firstdayofweek,
+                locale_weekdays: 'medium',
+                locale_months: 'long',
+                WEEKDAYS_MEDIUM: [
+                    config.sun,
+                    config.mon,
+                    config.tue,
+                    config.wed,
+                    config.thu,
+                    config.fri,
+                    config.sat ],
+                MONTHS_LONG: [
+                    config.january,
+                    config.february,
+                    config.march,
+                    config.april,
+                    config.may,
+                    config.june,
+                    config.july,
+                    config.august,
+                    config.september,
+                    config.october,
+                    config.november,
+                    config.december ],
             });
             this.calendar.changePageEvent.subscribe(function(){
                 this.fix_position();
index 306c4e5..d02d332 100644 (file)
@@ -79,7 +79,28 @@ function form_init_date_js() {
     if (!$done) {
         $module   = 'moodle-form-dateselector';
         $function = 'M.form.dateselector.init_date_selectors';
-        $config = array(array('firstdayofweek'=>get_string('firstdayofweek', 'langconfig')));
+        $config = array(array(
+            'firstdayofweek'    =>  get_string('firstdayofweek', 'langconfig'),
+            'mon'               => strftime('%a', 360000),      // 5th Jan 1970 at 12pm
+            'tue'               => strftime('%a', 446400),
+            'wed'               => strftime('%a', 532800),
+            'thu'               => strftime('%a', 619200),
+            'fri'               => strftime('%a', 705600),
+            'sat'               => strftime('%a', 792000),
+            'sun'               => strftime('%a', 878400),
+            'january'           => strftime('%B', 14400),       // 1st Jan 1970 at 12pm
+            'february'          => strftime('%B', 2692800),
+            'march'             => strftime('%B', 5112000),
+            'april'             => strftime('%B', 7790400),
+            'may'               => strftime('%B', 10382400),
+            'june'              => strftime('%B', 13060800),
+            'july'              => strftime('%B', 15652800),
+            'august'            => strftime('%B', 18331200),
+            'september'         => strftime('%B', 21009600),
+            'october'           => strftime('%B', 23601600),
+            'november'          => strftime('%B', 26280000),
+            'december'          => strftime('%B', 28872000)
+        ));
         $PAGE->requires->yui_module($module, $function, $config);
         $done = true;
     }
index 6bf2e28..66af621 100644 (file)
@@ -1771,14 +1771,27 @@ M.util.load_flowplayer = function() {
 
             var rule;
             for (var j=0; j < document.styleSheets.length; j++) {
-                if (typeof (document.styleSheets[j].rules) != 'undefined') {
-                    var allrules = document.styleSheets[j].rules;
-                } else if (typeof (document.styleSheets[j].cssRules) != 'undefined') {
-                    var allrules = document.styleSheets[j].cssRules;
-                } else {
-                    // why??
+
+                // To avoid javascript security violation accessing cross domain stylesheets
+                var allrules = false;
+                try {
+                    if (typeof (document.styleSheets[j].rules) != 'undefined') {
+                        allrules = document.styleSheets[j].rules;
+                    } else if (typeof (document.styleSheets[j].cssRules) != 'undefined') {
+                        allrules = document.styleSheets[j].cssRules;
+                    } else {
+                        // why??
+                        continue;
+                    }
+                } catch (e) {
                     continue;
                 }
+
+                // On cross domain style sheets Chrome V8 allows access to rules but returns null
+                if (!allrules) {
+                    continue;
+                }
+
                 for(var i=0; i<allrules.length; i++) {
                     rule = '';
                     if (/^\.mp3flowplayer_.*Color$/.test(allrules[i].selectorText)) {
index dc819aa..5c46983 100644 (file)
@@ -43,6 +43,10 @@ YUI.add('moodle-core-formchangechecker',
                  * get_form_dirty_state function later.
                  */
                 store_initial_value : function(e) {
+                    if (e.target.hasClass('ignoredirty')) {
+                        // Don't warn on elements with the ignoredirty class
+                        return;
+                    }
                     if (M.core_formchangechecker.get_form_dirty_state()) {
                         // Clear the store_initial_value listeners as the form is already dirty so
                         // we no longer need to call this function
@@ -88,7 +92,11 @@ YUI.add('moodle-core-formchangechecker',
         /**
          * Set the form changed state to true
          */
-        M.core_formchangechecker.set_form_changed = function() {
+        M.core_formchangechecker.set_form_changed = function(e) {
+            if (e.target.hasClass('ignoredirty')) {
+                // Don't warn on elements with the ignoredirty class
+                return;
+            }
             M.core_formchangechecker.stateinformation.formchanged = 1;
 
             // Once the form has been marked as dirty, we no longer need to keep track of form elements
index a6b2eb1..43c1e7d 100644 (file)
@@ -269,7 +269,7 @@ class assign_plugin_manager {
 
         if ($confirm) {
             // Delete any configuration records.
-            if (!unset_all_config_for_plugin('assignsubmission_' . $plugin)) {
+            if (!unset_all_config_for_plugin($this->subtype . '_' . $plugin)) {
                 $this->error = $OUTPUT->notification(get_string('errordeletingconfig', 'admin', $this->subtype . '_' . $plugin));
             }
 
@@ -282,7 +282,8 @@ class assign_plugin_manager {
             $DB->delete_records('assign_plugin_config', array('plugin'=>$plugin, 'subtype'=>$this->subtype));
 
             // Then the tables themselves
-            drop_plugin_tables($this->subtype . '_' . $plugin, $CFG->dirroot . '/mod/assign/' . $this->subtype . '/' .$plugin. '/db/install.xml', false);
+            $shortsubtype = substr($this->subtype, strlen('assign'));
+            drop_plugin_tables($this->subtype . '_' . $plugin, $CFG->dirroot . '/mod/assign/' . $shortsubtype . '/' .$plugin. '/db/install.xml', false);
 
             // Remove event handlers and dequeue pending events
             events_uninstall($this->subtype . '_' . $plugin);
index cf90c86..3e6e54b 100644 (file)
@@ -52,7 +52,9 @@ class mod_assign_grading_options_form extends moodleform {
         $options = array('' => get_string('filternone', 'assign'),
                          ASSIGN_FILTER_SUBMITTED => get_string('filtersubmitted', 'assign'),
                          ASSIGN_FILTER_REQUIRE_GRADING => get_string('filterrequiregrading', 'assign'));
-        $mform->addElement('select', 'filter', get_string('filter', 'assign'), $options);
+        if ($instance['submissionsenabled']) {
+            $mform->addElement('select', 'filter', get_string('filter', 'assign'), $options);
+        }
 
         // quickgrading
         if ($instance['showquickgrading']) {
index abd5b72..be0eb3d 100644 (file)
@@ -105,7 +105,7 @@ class assign_grading_table extends table_sql implements renderable {
             $where .= ' AND s.timecreated > 0 ';
         }
         if ($filter == ASSIGN_FILTER_REQUIRE_GRADING) {
-            $where .= ' AND (s.timemodified > g.timemodified OR g.timemodified IS NULL)';
+            $where .= ' AND (s.timemodified > g.timemodified OR (s.timemodified IS NOT NULL AND g.timemodified IS NULL))';
         }
         if (strpos($filter, ASSIGN_FILTER_SINGLE_USER) === 0) {
             $userfilter = (int) array_pop(explode('=', $filter));
index 251cff5..5b2438b 100644 (file)
@@ -173,6 +173,7 @@ $string['nousersselected'] = 'No users selected';
 $string['numberofdraftsubmissions'] = 'Drafts';
 $string['numberofparticipants'] = 'Participants';
 $string['numberofsubmittedassignments'] = 'Submitted';
+$string['numberofsubmissionsneedgrading'] = 'Needs grading';
 $string['offline'] = 'No online submissions required';
 $string['overdue'] = '<font color="red">Assignment is overdue by: {$a}</font>';
 $string['outlinegrade'] = 'Grade: {$a}';
@@ -206,7 +207,7 @@ $string['sendsubmissionreceipts_help'] = 'This switch will enable submission rec
 $string['settings'] = 'Assignment settings';
 $string['showrecentsubmissions'] = 'Show recent submissions';
 $string['submissiondrafts'] = 'Require students click submit button';
-$string['submissiondrafts_help'] = 'If enabled, students will have to click a Submit button to declare their submission as final. This allows students to keep a draft version of the submission on the system.';
+$string['submissiondrafts_help'] = 'If enabled, students will have to click a Submit button to declare their submission as final. This allows students to keep a draft version of the submission on the system. If this setting is changed from "No" to "Yes" after students have already submitted those submissions will be regarded as final.';
 $string['submissionnotready'] = 'This assignment is not ready to submit:';
 $string['submissionplugins'] = 'Submission plugins';
 $string['submissionreceipts'] = 'Send submission receipts';
index caccf10..a6cdba7 100644 (file)
@@ -212,16 +212,13 @@ function assign_print_overview($courses, &$htmlarray) {
     // Do assignment_base::isopen() here without loading the whole thing for speed
     foreach ($assignments as $key => $assignment) {
         $time = time();
+        $isopen = $assignment->allowsubmissionsfromdate <= $time;
         if ($assignment->duedate) {
             if ($assignment->preventlatesubmissions) {
-                $isopen = ($assignment->allowsubmissionsfromdate <= $time && $time <= $assignment->duedate);
-            } else {
-                $isopen = ($assignment->allowsubmissionsfromdate <= $time);
+                $isopen = ($isopen && $time <= $assignment->duedate);
             }
         }
-        if (empty($isopen) || empty($assignment->duedate)) {
-            $assignmentids[] = $assignment->id;
-        } else {
+        if ($isopen) {
             $assignmentids[] = $assignment->id;
         }
     }
@@ -265,6 +262,10 @@ function assign_print_overview($courses, &$htmlarray) {
                             AND a.id $sqlassignmentids", array_merge(array($USER->id, $USER->id), $assignmentidparams));
 
     foreach ($assignments as $assignment) {
+        // Do not show assignments that are not open
+        if (!in_array($assignment->id, $assignmentids)) {
+            continue;
+        }
         $str = '<div class="assign overview"><div class="name">'.$strassignment. ': '.
                '<a '.($assignment->visible ? '':' class="dimmed"').
                'title="'.$strassignment.'" href="'.$CFG->wwwroot.
index 2fef79b..8c538fd 100644 (file)
@@ -967,6 +967,27 @@ class assign {
         return count_enrolled_users($this->context, "mod/assign:submit", $currentgroup);
     }
 
+    /**
+     * Load a count of users submissions in the current module that require grading
+     * This means the submission modification time is more recent than the
+     * grading modification time.
+     *
+     * @return int number of matching submissions
+     */
+    public function count_submissions_need_grading() {
+        global $DB;
+
+        $params = array($this->get_course_module()->instance);
+
+        return $DB->count_records_sql("SELECT COUNT('x')
+                                       FROM {assign_submission} s
+                                       LEFT JOIN {assign_grades} g ON s.assignment = g.assignment AND s.userid = g.userid
+                                       WHERE s.assignment = ?
+                                           AND s.timemodified IS NOT NULL
+                                           AND (s.timemodified > g.timemodified OR g.timemodified IS NULL)",
+                                       $params);
+    }
+
     /**
      * Load a count of users enrolled in the current course with the specified permission and group (optional)
      *
@@ -1724,6 +1745,7 @@ class assign {
                                                                   array('cm'=>$this->get_course_module()->id,
                                                                         'contextid'=>$this->context->id,
                                                                         'userid'=>$USER->id,
+                                                                        'submissionsenabled'=>$this->is_any_submission_plugin_enabled(),
                                                                         'showquickgrading'=>$showquickgrading,
                                                                         'quickgrading'=>$quickgrading),
                                                                   'post', '',
@@ -1744,7 +1766,7 @@ class assign {
         if (!empty($CFG->enableplagiarism)) {
             /** Include plagiarismlib.php */
             require_once($CFG->libdir . '/plagiarismlib.php');
-            plagiarism_update_status($this->get_course(), $this->get_course_module());
+            $o .= plagiarism_update_status($this->get_course(), $this->get_course_module());
         }
 
         $actionformtext = $this->output->render($gradingactions);
@@ -1808,11 +1830,8 @@ class assign {
         if (!empty($CFG->enableplagiarism)) {
             /** Include plagiarismlib.php */
             require_once($CFG->libdir . '/plagiarismlib.php');
-            ob_start();
 
-            plagiarism_print_disclosure($this->get_course_module()->id);
-            $o = ob_get_contents();
-            ob_end_clean();
+            $o .= plagiarism_print_disclosure($this->get_course_module()->id);
         }
 
         return $o;
@@ -2094,7 +2113,8 @@ class assign {
                                                             $this->is_any_submission_plugin_enabled(),
                                                             $this->count_submissions_with_status(ASSIGN_SUBMISSION_STATUS_SUBMITTED),
                                                             $this->get_instance()->duedate,
-                                                            $this->get_course_module()->id
+                                                            $this->get_course_module()->id,
+                                                            $this->count_submissions_need_grading()
                                                             ));
         }
         $grade = $this->get_user_grade($USER->id, false);
@@ -2654,7 +2674,11 @@ class assign {
         // Need submit permission to submit an assignment
         require_capability('mod/assign:grade', $this->context);
 
-        $mform = new mod_assign_grading_options_form(null, array('cm'=>$this->get_course_module()->id, 'contextid'=>$this->context->id, 'userid'=>$USER->id, 'showquickgrading'=>false));
+        $mform = new mod_assign_grading_options_form(null, array('cm'=>$this->get_course_module()->id,
+                                                                 'contextid'=>$this->context->id,
+                                                                 'userid'=>$USER->id,
+                                                                 'submissionsenabled'=>$this->is_any_submission_plugin_enabled(),
+                                                                 'showquickgrading'=>false));
         if ($formdata = $mform->get_data()) {
             set_user_preference('assign_perpage', $formdata->perpage);
             set_user_preference('assign_filter', $formdata->filter);
index cb1daf9..5e710a4 100644 (file)
@@ -405,6 +405,8 @@ class assign_grading_summary implements renderable {
     var $submissionsenabled = false;
     /** @var int submissionssubmittedcount - The number of submissions in submitted status */
     var $submissionssubmittedcount = 0;
+    /** @var int submissionsneedgradingcount - The number of submissions that need grading */
+    var $submissionsneedgradingcount = 0;
     /** @var int duedate - The assignment due date (if one is set) */
     var $duedate = 0;
     /** @var int coursemoduleid - The assignment course module id */
@@ -421,7 +423,9 @@ class assign_grading_summary implements renderable {
      * @param int $duedate
      * @param int $coursemoduleid
      */
-    public function __construct($participantcount, $submissiondraftsenabled, $submissiondraftscount, $submissionsenabled, $submissionssubmittedcount, $duedate, $coursemoduleid) {
+    public function __construct($participantcount, $submissiondraftsenabled, $submissiondraftscount,
+                                $submissionsenabled, $submissionssubmittedcount,
+                                $duedate, $coursemoduleid, $submissionsneedgradingcount) {
         $this->participantcount = $participantcount;
         $this->submissiondraftsenabled = $submissiondraftsenabled;
         $this->submissiondraftscount = $submissiondraftscount;
@@ -429,6 +433,7 @@ class assign_grading_summary implements renderable {
         $this->submissionssubmittedcount = $submissionssubmittedcount;
         $this->duedate = $duedate;
         $this->coursemoduleid = $coursemoduleid;
+        $this->submissionsneedgradingcount = $submissionsneedgradingcount;
     }
 
 
index ab3af8a..8ffe18f 100644 (file)
@@ -248,6 +248,8 @@ class mod_assign_renderer extends plugin_renderer_base {
         if ($summary->submissionsenabled) {
             $this->add_table_row_tuple($t, get_string('numberofsubmittedassignments', 'assign'),
                                        $summary->submissionssubmittedcount);
+            $this->add_table_row_tuple($t, get_string('numberofsubmissionsneedgrading', 'assign'),
+                                       $summary->submissionsneedgradingcount);
         }
 
         $time = time();
index 187bc9a..95e2cfb 100644 (file)
@@ -50,8 +50,8 @@ if ($ADMIN->fulltree) {
 
     // The default here is feedback_comments (if it exists)
     $settings->add(new admin_setting_configselect('assign/feedback_plugin_for_gradebook',
-                   new lang_string('feedbackpluginforgradebook', 'mod_assign'),
-                   new lang_string('feedbackplugin', 'mod_assign'), 'assignfeedback_comments', $menu));
+                   new lang_string('feedbackplugin', 'mod_assign'),
+                   new lang_string('feedbackpluginforgradebook', 'mod_assign'), 'assignfeedback_comments', $menu));
     $settings->add(new admin_setting_configcheckbox('assign/showrecentsubmissions',
                    new lang_string('showrecentsubmissions', 'assign'),
                    new lang_string('configshowrecentsubmissions', 'assign'), 0));
index 8f8dcf3..eea2714 100644 (file)
@@ -1591,7 +1591,7 @@ class assignment_base {
                     }
                     $currentposition++;
                 }
-                if ($hassubmission && ($this->assignment->assignmenttype=='upload' || $this->assignment->assignmenttype=='online' || $this->assignment->assignmenttype=='uploadsingle')) { //TODO: this is an ugly hack, where is the plugin spirit? (skodak)
+                if ($hassubmission && method_exists($this, 'download_submissions')) {
                     echo html_writer::start_tag('div', array('class' => 'mod-assignment-download-link'));
                     echo html_writer::link(new moodle_url('/mod/assignment/submissions.php', array('id' => $this->cm->id, 'download' => 'zip')), get_string('downloadall', 'assignment'));
                     echo html_writer::end_tag('div');
index 71c0241..fc48974 100644 (file)
@@ -247,11 +247,11 @@ M.mod_chat_ajax.init = function(Y, cfg) {
                     li.all('td').item(1).append(Y.Node.create('<strong><a target="_blank" href="'+users[i].url+'">'+ users[i].name+'</a></strong>'));
                 } else {
                     li.all('td').item(1).append(Y.Node.create('<div><a target="_blank" href="'+users[i].url+'">'+users[i].name+'</a></div>'));
-                    var talk = Y.Node.create('<a href="###">'+M.str.chat.talk+'</a>&nbsp;');
+                    var talk = Y.Node.create('<a href="###">'+M.str.chat.talk+'</a>');
                     talk.on('click', this.talkto, this, users[i].name);
                     var beep = Y.Node.create('<a href="###">'+M.str.chat.beep+'</a>');
                     beep.on('click', this.send, this, users[i].id);
-                    li.all('td').item(1).append(Y.Node.create('<div></div>').append(talk).append(beep));
+                    li.all('td').item(1).append(Y.Node.create('<div></div>').append(talk).append('&nbsp;').append(beep));
                 }
                 list.append(li);
             }
index 07bbd19..ccbb949 100644 (file)
@@ -213,15 +213,17 @@ class mod_choice_renderer extends plugin_renderer_base {
                             $user->imagealt = '';
                         }
 
+                        $userfullname = fullname($user, $choices->fullnamecapability);
                         if ($choices->viewresponsecapability && $choices->deleterepsonsecapability  && $optionid > 0) {
-                            $attemptaction = html_writer::checkbox('attemptid[]', $user->id,'');
+                            $attemptaction = html_writer::label($userfullname, 'attempt-user'.$user->id, false, array('class' => 'accesshide'));
+                            $attemptaction .= html_writer::checkbox('attemptid[]', $user->id,'', null, array('id' => 'attempt-user'.$user->id));
                             $data .= html_writer::tag('div', $attemptaction, array('class'=>'attemptaction'));
                         }
                         $userimage = $this->output->user_picture($user, array('courseid'=>$choices->courseid));
                         $data .= html_writer::tag('div', $userimage, array('class'=>'image'));
 
                         $userlink = new moodle_url('/user/view.php', array('id'=>$user->id,'course'=>$choices->courseid));
-                        $name = html_writer::tag('a', fullname($user, $choices->fullnamecapability), array('href'=>$userlink, 'class'=>'username'));
+                        $name = html_writer::tag('a', $userfullname, array('href'=>$userlink, 'class'=>'username'));
                         $data .= html_writer::tag('div', $name, array('class'=>'fullname'));
                         $data .= html_writer::tag('div','', array('class'=>'clearfloat'));
                         $optionusers .= html_writer::tag('div', $data, array('class'=>'user'));
index 3040ef6..40fc894 100644 (file)
@@ -41,7 +41,7 @@ if (! $cm = get_coursemodule_from_instance('data', $data->id, $data->course)) {
 }
 
 if(! $course = $DB->get_record('course', array('id'=>$cm->course))) {
-    print_error('invalidcourseid', '', '', $cm->course);
+    print_error('invalidcourseid');
 }
 
 // fill in missing properties needed for updating of instance
index 812172a..4b7a8cc 100644 (file)
@@ -383,7 +383,7 @@ WHERE
  * @return string A unique message-id
  */
 function forum_get_email_message_id($postid, $usertoid, $hostname) {
-    return '<'.hash('sha256',$postid.'to'.$usertoid.'@'.$hostname).'>';
+    return '<'.hash('sha256',$postid.'to'.$usertoid).'@'.$hostname.'>';
 }
 
 /**
index c1bec7f..89fa16a 100644 (file)
@@ -275,7 +275,7 @@ M.mod_quiz.secure_window = {
         }, '#secureclosebutton');
     },
 
-    close: function(url, delay) {
+    close: function(Y, url, delay) {
         setTimeout(function() {
             if (window.opener) {
                 window.opener.document.location.reload();
index 165ec10..820e711 100644 (file)
@@ -509,8 +509,8 @@ class mod_quiz_renderer extends plugin_renderer_base {
             $output .= html_writer::tag('p', get_string('pleaseclose', 'quiz'));
             $delay = 0;
         }
-        $this->page->requires->js_function_call('M.mod_quiz.secure_window.close',
-                array($url, $delay));
+        $this->page->requires->js_init_call('M.mod_quiz.secure_window.close',
+                array($url, $delay), false, quiz_get_js_module());
 
         $output .= $this->box_end();
         $output .= $this->footer();
@@ -1149,6 +1149,24 @@ class mod_quiz_renderer extends plugin_renderer_base {
                 'id' => $cm->id, 'mode' => quiz_report_default_report($context)));
         return html_writer::link($url, $summary);
     }
+
+    /**
+     * Output a graph, or a message saying that GD is required.
+     * @param moodle_url $url the URL of the graph.
+     * @param string $title the title to display above the graph.
+     * @return string HTML fragment for the graph.
+     */
+    public function graph(moodle_url $url, $title) {
+        global $CFG;
+
+        if (empty($CFG->gdversion)) {
+            $graph = get_string('gdneed');
+        } else {
+            $graph = html_writer::empty_tag('img', array('src' => $url, 'alt' => $title));
+        }
+
+        return $this->heading($title) . html_writer::tag('div', $graph, array('class' => 'graph'));
+    }
 }
 
 class mod_quiz_links_to_other_attempts implements renderable {
index ae2e1f6..27b4df5 100644 (file)
@@ -40,7 +40,7 @@ require_once($CFG->dirroot . '/mod/quiz/report/overview/overview_table.php');
 class quiz_overview_report extends quiz_attempts_report {
 
     public function display($quiz, $cm, $course) {
-        global $CFG, $DB, $OUTPUT;
+        global $CFG, $DB, $OUTPUT, $PAGE;
 
         list($currentgroup, $students, $groupstudents, $allowed) =
                 $this->init('overview', 'quiz_overview_settings_form', $quiz, $cm, $course);
@@ -237,30 +237,25 @@ class quiz_overview_report extends quiz_attempts_report {
         }
 
         if (!$table->is_downloading() && $options->usercanseegrades) {
+            $output = $PAGE->get_renderer('mod_quiz');
             if ($currentgroup && $groupstudents) {
                 list($usql, $params) = $DB->get_in_or_equal($groupstudents);
                 $params[] = $quiz->id;
                 if ($DB->record_exists_select('quiz_grades', "userid $usql AND quiz = ?",
                         $params)) {
-                     $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php',
+                    $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php',
                             array('id' => $quiz->id, 'groupid' => $currentgroup));
-                     $graphname = get_string('overviewreportgraphgroup', 'quiz_overview',
+                    $graphname = get_string('overviewreportgraphgroup', 'quiz_overview',
                             groups_get_group_name($currentgroup));
-                     echo $OUTPUT->heading($graphname);
-                     echo html_writer::tag('div', html_writer::empty_tag('img',
-                            array('src' => $imageurl, 'alt' => $graphname)),
-                            array('class' => 'graph'));
+                    echo $output->graph($imageurl, $graphname);
                 }
             }
 
             if ($DB->record_exists('quiz_grades', array('quiz'=> $quiz->id))) {
-                 $graphname = get_string('overviewreportgraph', 'quiz_overview');
-                 $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php',
+                $imageurl = new moodle_url('/mod/quiz/report/overview/overviewgraph.php',
                         array('id' => $quiz->id));
-                 echo $OUTPUT->heading($graphname);
-                 echo html_writer::tag('div', html_writer::empty_tag('img',
-                        array('src' => $imageurl, 'alt' => $graphname)),
-                        array('class' => 'graph'));
+                $graphname = get_string('overviewreportgraph', 'quiz_overview');
+                echo $output->graph($imageurl, $graphname);
             }
         }
         return true;
index 99cbd31..48c91ee 100644 (file)
@@ -579,18 +579,17 @@ class quiz_statistics_report extends quiz_default_report {
      * @param int $quizstatsid the id of the statistics to show in the graph.
      */
     protected function output_statistics_graph($quizstatsid, $s) {
-        global $OUTPUT;
+        global $PAGE;
 
         if ($s == 0) {
             return;
         }
 
+        $output = $PAGE->get_renderer('mod_quiz');
         $imageurl = new moodle_url('/mod/quiz/report/statistics/statistics_graph.php',
                 array('id' => $quizstatsid));
-        $OUTPUT->heading(get_string('statisticsreportgraph', 'quiz_statistics'));
-        echo html_writer::tag('div', html_writer::empty_tag('img', array('src' => $imageurl,
-                'alt' => get_string('statisticsreportgraph', 'quiz_statistics'))),
-                array('class' => 'graph'));
+        $graphname = get_string('statisticsreportgraph', 'quiz_statistics');
+        echo $output->graph($imageurl, $graphname);
     }
 
     /**
index aa9e48d..03f42f1 100644 (file)
@@ -25,7 +25,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$module->version   = 2012061700;       // The current module version (Date: YYYYMMDDXX).
+$module->version   = 2012061701;       // The current module version (Date: YYYYMMDDXX).
 $module->requires  = 2012061700;    // Requires this Moodle version.
 $module->component = 'mod_quiz';       // Full name of the plugin (used for diagnostics).
 $module->cron      = 60;
index 27862e4..5a1bf0b 100644 (file)
@@ -127,25 +127,72 @@ class backup_scorm_activity_structure_step extends backup_activity_structure_ste
         // Define sources
         $scorm->set_source_table('scorm', array('id' => backup::VAR_ACTIVITYID));
 
-        $sco->set_source_table('scorm_scoes', array('scorm' => backup::VAR_PARENTID));
-
-        $scodata->set_source_table('scorm_scoes_data', array('scoid' => backup::VAR_PARENTID));
-
-        $seqrulecond->set_source_table('scorm_seq_ruleconds', array('scoid' => backup::VAR_PARENTID));
-
-        $seqrulecondsdata->set_source_table('scorm_seq_rulecond', array('ruleconditionsid' => backup::VAR_PARENTID));
-
-        $seqrolluprule->set_source_table('scorm_seq_rolluprule', array('scoid' => backup::VAR_PARENTID));
-
-        $seqrolluprulecond->set_source_table('scorm_seq_rolluprulecond', array('rollupruleid' => backup::VAR_PARENTID));
-
-        $seqobjective->set_source_table('scorm_seq_objective', array('scoid' => backup::VAR_PARENTID));
-
-        $seqmapinfo->set_source_table('scorm_seq_mapinfo', array('objectiveid' => backup::VAR_PARENTID));
+        // Use set_source_sql for other calls as set_source_table returns records in reverse order
+        // and order is important for several SCORM fields - esp scorm_scoes.
+        $sco->set_source_sql('
+                SELECT *
+                FROM {scorm_scoes}
+                WHERE scorm = :scorm
+                ORDER BY id',
+            array('scorm' => backup::VAR_PARENTID));
+
+        $scodata->set_source_sql('
+                SELECT *
+                FROM {scorm_scoes_data}
+                WHERE scoid = :scoid
+                ORDER BY id',
+            array('scoid' => backup::VAR_PARENTID));
+
+        $seqrulecond->set_source_sql('
+                SELECT *
+                FROM {scorm_seq_ruleconds}
+                WHERE scoid = :scoid
+                ORDER BY id',
+            array('scoid' => backup::VAR_PARENTID));
+
+        $seqrulecondsdata->set_source_sql('
+                SELECT *
+                FROM {scorm_seq_rulecond}
+                WHERE ruleconditionsid = :ruleconditionsid
+                ORDER BY id',
+            array('ruleconditionsid' => backup::VAR_PARENTID));
+
+        $seqrolluprule->set_source_sql('
+                SELECT *
+                FROM {scorm_seq_rolluprule}
+                WHERE scoid = :scoid
+                ORDER BY id',
+            array('scoid' => backup::VAR_PARENTID));
+
+        $seqrolluprulecond->set_source_sql('
+                SELECT *
+                FROM {scorm_seq_rolluprulecond}
+                WHERE rollupruleid = :rollupruleid
+                ORDER BY id',
+            array('rollupruleid' => backup::VAR_PARENTID));
+
+        $seqobjective->set_source_sql('
+                SELECT *
+                FROM {scorm_seq_objective}
+                WHERE scoid = :scoid
+                ORDER BY id',
+            array('scoid' => backup::VAR_PARENTID));
+
+        $seqmapinfo->set_source_sql('
+                SELECT *
+                FROM {scorm_seq_mapinfo}
+                WHERE objectiveid = :objectiveid
+                ORDER BY id',
+            array('objectiveid' => backup::VAR_PARENTID));
 
         // All the rest of elements only happen if we are including user info
         if ($userinfo) {
-            $scotrack->set_source_table('scorm_scoes_track', array('scoid' => backup::VAR_PARENTID));
+            $scotrack->set_source_sql('
+                SELECT *
+                FROM {scorm_scoes_track}
+                WHERE scoid = :scoid
+                ORDER BY id',
+                array('scoid' => backup::VAR_PARENTID));
         }
 
         // Define id annotations
index b251127..43c5395 100644 (file)
@@ -221,6 +221,18 @@ class scorm_interactions_report extends scorm_default_report {
                 $table->no_sorting('finish');
                 $table->no_sorting('score');
 
+                for($id = 0; $id < $questioncount; $id++) {
+                    if ($displayoptions['qtext']) {
+                        $table->no_sorting('question'.$id);
+                    }
+                    if ($displayoptions['resp']) {
+                        $table->no_sorting('response'.$id);
+                    }
+                    if ($displayoptions['right']) {
+                        $table->no_sorting('right'.$id);
+                    }
+                }
+
                 foreach ($scoes as $sco) {
                     if ($sco->launch != '') {
                         $table->no_sorting('scograde'.$sco->id);
index fc31e9b..f671042 100644 (file)
@@ -110,7 +110,7 @@ class core_notes_external extends external_api {
             //check the course exists
             if (empty($courses[$note['courseid']])) {
                 $success = false;
-                $errormessage = get_string('invalidcourseid', 'notes', $note['courseid']);
+                $errormessage = get_string('invalidcourseid', 'error');
             } else {
                 // Ensure the current user is allowed to run this function
                 $context = get_context_instance(CONTEXT_COURSE, $note['courseid']);
index 0405ba5..a7b87d0 100644 (file)
@@ -108,7 +108,9 @@ class portfolio_plugin_googledocs extends portfolio_plugin_push_base {
         $mform->addElement('static', null, '', get_string('oauthinfo', 'portfolio_googledocs', $a));
 
         $mform->addElement('text', 'clientid', get_string('clientid', 'portfolio_googledocs'));
+        $mform->setType('clientid', PARAM_RAW_TRIMMED);
         $mform->addElement('text', 'secret', get_string('secret', 'portfolio_googledocs'));
+        $mform->setType('secret', PARAM_RAW_TRIMMED);
 
         $strrequired = get_string('required');
         $mform->addRule('clientid', $strrequired, 'required', null, 'client');
index cbef42c..fff8760 100644 (file)
@@ -108,7 +108,9 @@ class portfolio_plugin_picasa extends portfolio_plugin_push_base {
         $mform->addElement('static', null, '', get_string('oauthinfo', 'portfolio_picasa', $a));
 
         $mform->addElement('text', 'clientid', get_string('clientid', 'portfolio_picasa'));
+        $mform->setType('clientid', PARAM_RAW_TRIMMED);
         $mform->addElement('text', 'secret', get_string('secret', 'portfolio_picasa'));
+        $mform->setType('secret', PARAM_RAW_TRIMMED);
 
         $strrequired = get_string('required');
         $mform->addRule('clientid', $strrequired, 'required', null, 'client');
index 5dd1e86..9f1b67b 100644 (file)
@@ -68,8 +68,8 @@ class restore_qtype_shortanswer_plugin extends restore_qtype_plugin {
         $questioncreated = $this->get_mappingid('question_created', $oldquestionid) ? true : false;
 
         // If the question has been created by restore, we need to create its
-        // question_shortanswer too
-        if ($questioncreated) {
+        // question_shortanswer too, if they are defined (the gui should ensure this).
+        if ($questioncreated && !empty($data->answers)) {
             // Adjust some columns
             $data->question = $newquestionid;
             // Map sequence of question_answer ids
index d23f361..7c4e1f4 100644 (file)
@@ -1737,7 +1737,7 @@ M.core_filepicker.init = function(Y, options) {
                 setAttrs({id:'fp-tb-help-'+client_id+'-link', target:'_blank'}).
                 setStyle('display', 'none');
             toolbar.append(helplnk);
-            toolbar.one('.fp-tb-manage').one('a,button').
+            toolbar.one('.fp-tb-help').one('a,button').
                 on('click', function(e) {
                     e.preventDefault();
                     helplnk.simulate('click')
index ee56c02..c3a00e1 100644 (file)
@@ -119,7 +119,9 @@ class repository_googledocs extends repository {
 
         parent::type_config_form($mform);
         $mform->addElement('text', 'clientid', get_string('clientid', 'repository_googledocs'));
+        $mform->setType('clientid', PARAM_RAW_TRIMMED);
         $mform->addElement('text', 'secret', get_string('secret', 'repository_googledocs'));
+        $mform->setType('secret', PARAM_RAW_TRIMMED);
 
         $strrequired = get_string('required');
         $mform->addRule('clientid', $strrequired, 'required', null, 'client');
index 642c7b3..11f8eb0 100644 (file)
@@ -118,7 +118,9 @@ class repository_picasa extends repository {
 
         parent::type_config_form($mform);
         $mform->addElement('text', 'clientid', get_string('clientid', 'repository_picasa'));
+        $mform->setType('clientid', PARAM_RAW_TRIMMED);
         $mform->addElement('text', 'secret', get_string('secret', 'repository_picasa'));
+        $mform->setType('secret', PARAM_RAW_TRIMMED);
 
         $strrequired = get_string('required');
         $mform->addRule('clientid', $strrequired, 'required', null, 'client');
index 09dc4b2..d073270 100644 (file)
@@ -167,7 +167,7 @@ input.titleeditor {
 
 /* Course drag and drop upload styles */
 #dndupload-status {width:40%;margin:0 30%;padding:6px;border:1px solid #ddd;text-align:center;background:#ffc;position:absolute;z-index:9999;box-shadow:2px 2px 5px 1px #ccc;border-radius:0px 0px 8px 8px;z-index: 0;}
-.dndupload-preview {color:#909090;border:1px dashed #909090;}
+.dndupload-preview {color:#909090;border:1px dashed #909090;list-style:none;}
 .dndupload-progress-outer {width:70px;border:1px solid black;height:10px;display:inline-block;margin:0;padding:0;overflow:hidden;position:relative;}
 .dndupload-progress-inner {width:0%;height:100%;background-color:green;display:inline-block;margin:0;padding:0;float:left;}
 .dndupload-hidden {display:none;}
index 836233a..5fbacc3 100644 (file)
@@ -290,7 +290,7 @@ a.ygtvspacer:hover {color: transparent;text-decoration: none;}
 /*.filemanager-container ul{margin:0;padding:0;}
 .filemanager-container ul li{white-space:nowrap;list-style-type:none;}
 .filemanager-container ul li a{padding:0}*/
-.filemanager .fp-content{overflow: auto;max-height: 472px;}
+.filemanager .fp-content{overflow: auto;max-height: 472px;min-height: 157px;}
 .filemanager-container, .filepicker-filelist {overflow:hidden;}
 
 /*
index 246fae2..1e9ff4b 100644 (file)
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062501.02;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062501.03;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.1+ (Build: 20120712)';   // Human-friendly version name
+$release  = '2.3.1+ (Build: 20120719)';   // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level