Merge branch 'wip-MDL-35661-MOODLE_23_STABLE' of git://github.com/marinaglancy/moodle...
authorDan Poltawski <dan@moodle.com>
Mon, 15 Oct 2012 05:31:22 +0000 (13:31 +0800)
committerDan Poltawski <dan@moodle.com>
Mon, 15 Oct 2012 05:31:22 +0000 (13:31 +0800)
48 files changed:
admin/cli/install.php
admin/renderer.php
admin/tool/customlang/locallib.php
admin/tool/xmldb/lang/en/tool_xmldb.php
course/dndupload.js
course/dnduploadlib.php
course/lib.php
course/tests/courselib_test.php
course/tests/externallib_test.php
course/yui/dragdrop/dragdrop.js
enrol/ajax.php
enrol/manual/ajax.php
enrol/manual/manage.php
install/lang/he/error.php
install/lang/he/install.php
install/lang/ro/install.php
install/lang/sr_cr/install.php
lang/en/mimetypes.php
lib/enrollib.php
lib/filelib.php
lib/formslib.php
lib/grade/grade_category.php
lib/grade/tests/grade_category_test.php
lib/navigationlib.php
lib/phpunit/classes/util.php
mod/assign/gradingoptionsform.php
mod/assign/lang/en/assign.php
mod/assign/lib.php
mod/assign/locallib.php
mod/book/lang/en/book.php
mod/book/tool/importhtml/index.php
mod/book/view.php
mod/data/lib.php
mod/data/tests/fixtures/test_data_records.csv
mod/data/tests/search_test.php
mod/data/view.php
mod/quiz/styles.css
mod/upgrade.txt
pix/f/epub.png [new file with mode: 0644]
question/type/multianswer/module.js
question/type/multianswer/renderer.php
repository/upload/lang/en/repository_upload.php
theme/base/style/core.css
theme/formal_white/lang/en/theme_formal_white.php
theme/serenity/style/core.css
user/selector/module.js
user/selector/search.php
version.php

index 79ff0b7..38aa06e 100644 (file)
@@ -240,18 +240,8 @@ echo get_string('cliinstallheader', 'install', $CFG->target_release)."\n";
 if ($interactive) {
     cli_separator();
     $languages = get_string_manager()->get_list_of_translations();
-    // format the langs nicely - 3 per line
-    $c = 0;
-    $langlist = '';
-    foreach ($languages as $key=>$lang) {
-        $c++;
-        $length = iconv_strlen($lang, 'UTF-8');
-        $padded = $lang.str_repeat(' ', 38-$length);
-        $langlist .= $padded;
-        if ($c % 3 == 0) {
-            $langlist .= "\n";
-        }
-    }
+    // Do not put the langs into columns because it is not compatible with RTL.
+    $langlist = implode("\n", $languages);
     $default = $CFG->lang;
     cli_heading(get_string('availablelangs', 'install'));
     echo $langlist."\n";
index 3a3c2bd..56c9056 100644 (file)
@@ -470,7 +470,7 @@ class core_admin_renderer extends plugin_renderer_base {
         $copyrighttext = '<a href="http://moodle.org/">Moodle</a> '.
                          '<a href="http://docs.moodle.org/dev/Releases" title="'.$CFG->version.'">'.$CFG->release.'</a><br />'.
                          'Copyright &copy; 1999 onwards, Martin Dougiamas<br />'.
-                         'and <a href="http://docs.moodle.org/dev/Credits">many other contributors</a>.<br />'.
+                         'and <a href="http://moodle.org/dev">many other contributors</a>.<br />'.
                          '<a href="http://docs.moodle.org/dev/License">GNU Public License</a>';
         //////////////////////////////////////////////////////////////////////////////////////////////////
 
index 47bbdfa..878eb4c 100644 (file)
@@ -488,7 +488,7 @@ class tool_customlang_translator implements renderable {
         list($insql, $inparams) = $DB->get_in_or_equal($filter->component, SQL_PARAMS_NAMED);
 
         $csql = "SELECT COUNT(*)";
-        $fsql = "SELECT s.id, s.*, c.name AS component";
+        $fsql = "SELECT s.*, c.name AS component";
         $sql  = "  FROM {tool_customlang_components} c
                    JOIN {tool_customlang} s ON s.componentid = c.id
                   WHERE s.lang = :lang
index 7b384b2..c1475be 100644 (file)
@@ -111,10 +111,13 @@ $string['checkindexes'] = 'Check indexes';
 $string['check_indexes'] = 'Look for missing DB indexes';
 $string['checkoraclesemantics'] = 'Check semantics';
 $string['check_oracle_semantics'] = 'Look for incorrect length semantics';
+$string['duplicateindexname'] = 'Duplicate index name';
 $string['incorrectfieldname'] = 'Incorrect name';
 $string['index'] = 'Index';
 $string['indexes'] = 'Indexes';
+$string['indexnameempty'] = 'Index name is empty';
 $string['integerincorrectlength'] = 'Incorrect length for integer field';
+$string['incorrectindexname'] = 'Incorrect index name';
 $string['incorrectkeyname'] = 'Incorrect key name';
 $string['incorrecttablename'] = 'Incorrect table name';
 $string['key'] = 'Key';
index 7bfef1d..2dcaa13 100644 (file)
@@ -445,6 +445,7 @@ M.course_dndupload = {
             a: document.createElement('a'),
             icon: document.createElement('img'),
             namespan: document.createElement('span'),
+            groupingspan: document.createElement('span'),
             progressouter: document.createElement('span'),
             progress: document.createElement('span')
         };
@@ -469,6 +470,9 @@ M.course_dndupload = {
 
         resel.div.appendChild(document.createTextNode(' '));
 
+        resel.groupingspan.className = 'groupinglabel';
+        resel.div.appendChild(resel.groupingspan);
+
         resel.progressouter.className = 'dndupload-progress-outer';
         resel.progress.className = 'dndupload-progress-inner';
         resel.progress.innerHTML = '&nbsp;';
@@ -724,6 +728,13 @@ M.course_dndupload = {
                             resel.icon.src = result.icon;
                             resel.a.href = result.link;
                             resel.namespan.innerHTML = result.name;
+
+                            if (result.groupingname) {
+                                resel.groupingspan.innerHTML = '(' + result.groupingname + ')';
+                            } else {
+                                resel.div.removeChild(resel.groupingspan);
+                            }
+
                             resel.div.removeChild(resel.progressouter);
                             resel.li.id = result.elementid;
                             resel.div.innerHTML += result.commands;
@@ -904,6 +915,13 @@ M.course_dndupload = {
                             resel.icon.src = result.icon;
                             resel.a.href = result.link;
                             resel.namespan.innerHTML = result.name;
+
+                            if (result.groupingname) {
+                                resel.groupingspan.innerHTML = '(' + result.groupingname + ')';
+                            } else {
+                                resel.div.removeChild(resel.groupingspan);
+                            }
+
                             resel.div.removeChild(resel.progressouter);
                             resel.li.id = result.elementid;
                             resel.div.innerHTML += result.commands;
index 816924b..038c09b 100644 (file)
@@ -667,6 +667,12 @@ class dndupload_ajax_processor {
         $resp->commands = make_editing_buttons($mod, true, true, 0, $mod->sectionnum);
         $resp->onclick = $mod->get_on_click();
 
+        // if using groupings, then display grouping name
+        if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', $this->context)) {
+            $groupings = groups_get_all_groupings($this->course->id);
+            $resp->groupingname = format_string($groupings[$mod->groupingid]->name);
+        }
+
         echo $OUTPUT->header();
         echo json_encode($resp);
         die();
index 955b58c..ef150d0 100644 (file)
@@ -531,7 +531,7 @@ function print_mnet_log($hostid, $course, $user=0, $date=0, $order="l.time ASC",
 
 function print_log_csv($course, $user, $date, $order='l.time DESC', $modname,
                         $modid, $modaction, $groupid) {
-    global $DB;
+    global $DB, $CFG;
 
     $text = get_string('course')."\t".get_string('time')."\t".get_string('ip_address')."\t".
             get_string('fullnameuser')."\t".get_string('action')."\t".get_string('info');
@@ -600,6 +600,8 @@ function print_log_csv($course, $user, $date, $order='l.time DESC', $modname,
         $firstField = format_string($courses[$log->course], true, array('context' => $coursecontext));
         $fullname = fullname($log, has_capability('moodle/site:viewfullnames', $coursecontext));
         $row = array($firstField, userdate($log->time, $strftimedatetime), $log->ip, $fullname, $log->module.' '.$log->action, $log->info);
+        $actionurl = $CFG->wwwroot. make_log_url($log->module,$log->url);\r
+        $row = array($firstField, userdate($log->time, $strftimedatetime), $log->ip, $fullname, $log->module.' '.$log->action.' ('.$actionurl.')', $log->info);
         $text = implode("\t", $row);
         echo $text." \n";
     }
@@ -710,7 +712,8 @@ function print_log_xls($course, $user, $date, $order='l.time DESC', $modname,
         $myxls->write($row, 2, $log->ip, '');
         $fullname = fullname($log, has_capability('moodle/site:viewfullnames', $coursecontext));
         $myxls->write($row, 3, $fullname, '');
-        $myxls->write($row, 4, $log->module.' '.$log->action, '');
+        $actionurl = $CFG->wwwroot. make_log_url($log->module,$log->url);
+        $myxls->write($row, 4, $log->module.' '.$log->action.' ('.$actionurl.')', '');
         $myxls->write($row, 5, $log->info, '');
 
         $row++;
@@ -823,7 +826,8 @@ function print_log_ods($course, $user, $date, $order='l.time DESC', $modname,
         $myxls->write_string($row, 2, $log->ip);
         $fullname = fullname($log, has_capability('moodle/site:viewfullnames', $coursecontext));
         $myxls->write_string($row, 3, $fullname);
-        $myxls->write_string($row, 4, $log->module.' '.$log->action);
+        $actionurl = $CFG->wwwroot. make_log_url($log->module,$log->url);
+        $myxls->write_string($row, 4, $log->module.' '.$log->action.' ('.$actionurl.')');
         $myxls->write_string($row, 5, $log->info);
 
         $row++;
@@ -1572,7 +1576,7 @@ function print_section($course, $section, $mods, $modnamesused, $absolute=false,
                     // Display link itself
                     echo '<a ' . $linkcss . $mod->extra . $onclick .
                             ' href="' . $url . '"><img src="' . $mod->get_icon_url() .
-                            '" class="activityicon" alt="" /> ' .
+                            '" class="activityicon" alt="' . $modulename . '" /> ' .
                             $accesstext . '<span class="instancename">' .
                             $instancename . $altname . '</span></a>';
 
index 42b8057..acf5963 100644 (file)
@@ -36,7 +36,7 @@ class courselib_testcase extends advanced_testcase {
         $course = $this->getDataGenerator()->create_course(array('numsections'=>10), array('createsections'=>true));
         $oldsections = array();
         $sections = array();
-        foreach ($DB->get_records('course_sections', array('course'=>$course->id)) as $section) {
+        foreach ($DB->get_records('course_sections', array('course'=>$course->id), 'id') as $section) {
             $oldsections[$section->section] = $section->id;
             $sections[$section->id] = $section->section;
         }
index 605c5d8..984b9ed 100644 (file)
@@ -580,6 +580,5 @@ class core_course_external_testcase extends externallib_advanced_testcase {
 
         // Check that the course has been duplicated.
         $this->assertEquals($newcourse['shortname'], $duplicate['shortname']);
-        gc_collect_cycles();
     }
 }
index f52497e..bd35bd9 100644 (file)
@@ -294,13 +294,13 @@ YUI.add('moodle-course-dragdrop', function(Y) {
                     var resources = Y.Node.create('<ul></ul>');
                     resources.addClass(CSS.SECTION);
                     sectionnode.one('.'+CSS.CONTENT+' div.'+CSS.SUMMARY).insert(resources, 'after');
-                    // Define empty ul as droptarget, so that item could be moved to empty list
-                    var tar = new Y.DD.Drop({
-                        node: resources,
-                        groups: this.groups,
-                        padding: '20 0 20 0'
-                    });
                 }
+                // Define empty ul as droptarget, so that item could be moved to empty list
+                var tar = new Y.DD.Drop({
+                    node: resources,
+                    groups: this.groups,
+                    padding: '20 0 20 0'
+                });
 
                 // Initialise each resource/activity in this section
                 this.setup_for_resource('#'+sectionnode.get('id')+' li.'+CSS.ACTIVITY);
index 8a0bdfc..48b3fca 100644 (file)
@@ -54,9 +54,9 @@ echo $OUTPUT->header(); // send headers
 
 $manager = new course_enrolment_manager($PAGE, $course);
 
-$outcome = new stdClass;
+$outcome = new stdClass();
 $outcome->success = true;
-$outcome->response = new stdClass;
+$outcome->response = new stdClass();
 $outcome->error = '';
 
 switch ($action) {
@@ -99,6 +99,10 @@ switch ($action) {
             $user->fullname = fullname($user);
             unset($user->id);
         }
+        // Chrome will display users in the order of the array keys, so we need
+        // to ensure that the results ordered array keys. Fortunately, the JavaScript
+        // does not care what the array keys are. It uses user.id where necessary.
+        $outcome->response['users'] = array_values($outcome->response['users']);
         $outcome->success = true;
         break;
     default:
index a9d5bb7..b599b95 100644 (file)
@@ -53,9 +53,9 @@ echo $OUTPUT->header(); // send headers
 
 $manager = new course_enrolment_manager($PAGE, $course);
 
-$outcome = new stdClass;
+$outcome = new stdClass();
 $outcome->success = true;
-$outcome->response = new stdClass;
+$outcome->response = new stdClass();
 $outcome->error = '';
 
 switch ($action) {
@@ -79,6 +79,10 @@ switch ($action) {
             }
             $user->extrafields = implode(', ', $fieldvalues);
         }
+        // Chrome will display users in the order of the array keys, so we need
+        // to ensure that the results ordered array keys. Fortunately, the JavaScript
+        // does not care what the array keys are. It uses user.id where necessary.
+        $outcome->response['users'] = array_values($outcome->response['users']);
         $outcome->success = true;
         break;
     case 'enrol':
@@ -135,4 +139,4 @@ switch ($action) {
         throw new enrol_ajax_exception('unknowajaxaction');
 }
 
-echo json_encode($outcome);
\ No newline at end of file
+echo json_encode($outcome);
index f7ea7e2..f458a91 100644 (file)
@@ -64,7 +64,7 @@ $PAGE->set_heading($course->fullname);
 navigation_node::override_active_url(new moodle_url('/enrol/users.php', array('id'=>$course->id)));
 
 // Create the user selector objects.
-$options = array('enrolid' => $enrolid);
+$options = array('enrolid' => $enrolid, 'accesscontext' => $context);
 
 $potentialuserselector = new enrol_manual_potential_participant('addselect', $options);
 $currentuserselector = new enrol_manual_current_participant('removeselect', $options);
index 6a2e548..fe6d20a 100644 (file)
@@ -33,13 +33,13 @@ defined('MOODLE_INTERNAL') || die();
 $string['cannotcreatelangdir'] = 'לא ניתן ליצור סיפריית שפה.';
 $string['cannotcreatetempdir'] = 'לא ניתן ליצור סיפרייה זמנית.';
 $string['cannotdownloadcomponents'] = 'לא ניתן להוריד רכיבים.';
-$string['cannotdownloadzipfile'] = 'לא ניתן להוריד קובץ ZIP.';
+$string['cannotdownloadzipfile'] = 'לא ניתן להוריד קובץ 7Zip';
 $string['cannotfindcomponent'] = 'הרכיב לא נמצא.';
 $string['cannotsavemd5file'] = 'לא ניתן לשמור קובץ md5.';
 $string['cannotsavezipfile'] = 'לא ניתן לשמור קובץ ZIP.';
 $string['cannotunzipfile'] = 'לא ניתן לפתוח את קובץ ה-ZIP.';
 $string['componentisuptodate'] = 'הרכיב מעודכן.';
-$string['downloadedfilecheckfailed'] = '× ×\9bש×\9c×\94 ×\91×\93×\99קת ×\94ק×\95×\91×¥ ×\94×\9e×\95ר×\93.';
+$string['downloadedfilecheckfailed'] = '×\94ק×\95×\91×¥ ×\90שר ×\99ר×\93 × ×\9eצ×\90 ×©×\92×\95×\99';
 $string['invalidmd5'] = 'md5 לא חוקי';
 $string['missingrequiredfield'] = 'חסר שדה נדרש כלשהו';
 $string['remotedownloaderror'] = 'הורדת הרכיב לשרת שלך כשלה, אנא וודא את הגדרות ה-proxy שלך. תוספת PHP cURL מומלצת מאוד להתקנה.
index d6cb0ae..52508ae 100644 (file)
@@ -101,11 +101,9 @@ $string['welcomep40'] = 'החבילה כוללת בנוסף
 $string['welcomep50'] = 'השימוש בכל היישומים בחבילה זו מפוקח ע"י הרשיונות המתאימים להם. החבילה
 <strong>{$a->installername}</strong>
 השלמה היא
-<a href="http://www.opensource.org/docs/definition_plain.html"> קוד פתוח
-</a>
-והיא מבוזרת תחת רישיון
-<a>
-href="http://www.gnu.org/copyleft/gpl.html">GPL</a>';
+<a href="http://www.opensource.org/docs/definition_plain.html">קוד פתוח</a>
+והיא מופצת תחת רשיון
+<a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>';
 $string['welcomep60'] = 'העמודים הבאים יובילו אותך בצורה פשוטה דרך כמה צעדים לעיצוב הגדרות <strong>Moodle</strong> במחשבך.
 תוכל לאשר את הגדרות  ברירת המחדל או, באפשרותך, לשנותם לפי צרכיך.';
 $string['welcomep70'] = 'הקש על לחצן ה"המשך" למטה כדי להמשיך עם הגדרת ה-<strong>Moodle</strong>';
index 1971fb3..ec01ae5 100644 (file)
 
 defined('MOODLE_INTERNAL') || die();
 
-$string['admindirname'] = 'Admin Directory';
+$string['admindirname'] = 'Director Admin';
 $string['availablelangs'] = 'Pachete de limbă disponibile';
 $string['chooselanguagehead'] = 'Selectare limbă';
 $string['chooselanguagesub'] = 'Vă rugăm selectaţi limba pentru interfaţa de instalare, limba selectată va fi folosită EXCLUSIV în cadrul procedurii de instalare. Ulterior veţi putea selecta limba în care doriţi să fie afişată interfaţa.';
-$string['dataroot'] = 'Data Directory';
+$string['databasehost'] = 'Gazdă baza de date';
+$string['databasename'] = 'Nume baza de date';
+$string['databasetypehead'] = 'Alegere driver baza de date';
+$string['dataroot'] = 'Director date';
+$string['datarootpermission'] = 'Permisiuni directoare date';
 $string['dbprefix'] = 'Prefix tabele';
 $string['dirroot'] = 'Director Moodle';
 $string['environmenthead'] = 'Se verifică mediul...';
 $string['installation'] = 'Instalare';
+$string['paths'] = 'Căi';
+$string['pathshead'] = 'Confirmare căi';
+$string['phpextension'] = 'extensie PHP {$a}';
 $string['phpversion'] = 'Versiune PHP';
 $string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
 $string['wwwroot'] = 'Adresă Web';
index 1dc0ec5..6a243d6 100644 (file)
@@ -45,7 +45,7 @@ $string['datarootpermission'] = 'Овлашћења над директориј
 $string['dbprefix'] = 'Префикс табеле';
 $string['dirroot'] = 'Moodle директоријум';
 $string['environmenthead'] = 'Проверавање Вашег окружења...';
-$string['environmentsub2'] = 'Свака верзија Moodlea има минимум захтева по питању одговарајуће PHP верѕије и неколико обавезних PHP екстензија.
+$string['environmentsub2'] = 'Свака верзија Moodlea има минимум захтева по питању одговарајуће PHP верзије и неколико обавезних PHP екстензија.
 Пуна провера окружења се врши пре сваке инсталације или ажурирања постојеће верзије. Уколико не знате како да инсталирате нову верзију или омогућите PHP ектензије контактирајте Вашег сервер администратора.';
 $string['errorsinenvironment'] = 'Провера окружења није прошла!';
 $string['installation'] = 'Инсталација';
@@ -75,7 +75,7 @@ $string['pathssubwwwroot'] = 'Пуна веб адреса путем које 
 Ако је адреса нетачна промените URL у свом веб читачу да бисте поново покренули инсталацију са другачијом вредношћу.';
 $string['pathsunsecuredataroot'] = 'Dataroot локација није безбедна';
 $string['pathswrongadmindir'] = 'Админ директоријум не постоји';
-$string['phpextension'] = '{$a} PHP екстенѕија';
+$string['phpextension'] = '{$a} PHP екстензија';
 $string['phpversion'] = 'PHP верзија';
 $string['phpversionhelp'] = '<p>Moodle захтева најмање PHP верзију 4.3.0 или 5.1.0 (5.0.x има  бројне уочене проблеме).</p>
 <p>Тренутно користите верзију {$a}</p>
index 9cb966d..64624fb 100644 (file)
@@ -46,6 +46,7 @@ $string['application/vnd.openxmlformats-officedocument.presentationml.slideshow'
 $string['application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] = 'Excel spreadsheet';
 $string['application/vnd.openxmlformats-officedocument.spreadsheetml.template'] = 'Excel template';
 $string['application/vnd.openxmlformats-officedocument.wordprocessingml.document'] = 'Word document';
+$string['application/epub_zip'] = 'EPUB ebook';
 $string['archive'] = 'Archive ({$a->EXT})';
 $string['audio'] = 'Audio file ({$a->EXT})';
 $string['default'] = '{$a->mimetype}';
index b6736c4..bb609fc 100644 (file)
@@ -1626,7 +1626,7 @@ abstract class enrol_plugin {
         $participants->close();
 
         // now clean up all remainders that were not removed correctly
-        $DB->delete_records('role_assignments', array('itemid'=>$instance->id, 'component'=>$name));
+        $DB->delete_records('role_assignments', array('itemid'=>$instance->id, 'component'=>'enrol_'.$name));
         $DB->delete_records('user_enrolments', array('enrolid'=>$instance->id));
 
         // finally drop the enrol row
index 7c2087e..465ba24 100644 (file)
@@ -1404,6 +1404,7 @@ function &get_mimetypes_array() {
         'dir'  => array ('type'=>'application/x-director', 'icon'=>'flash'),
         'dxr'  => array ('type'=>'application/x-director', 'icon'=>'flash'),
         'eps'  => array ('type'=>'application/postscript', 'icon'=>'eps'),
+        'epub' => array ('type'=>'application/epub+zip', 'icon'=>'epub', 'groups'=>array('document')),
         'fdf'  => array ('type'=>'application/pdf', 'icon'=>'pdf'),
         'flv'  => array ('type'=>'video/x-flv', 'icon'=>'flash', 'groups'=>array('video','web_video'), 'string'=>'video'),
         'f4v'  => array ('type'=>'video/mp4', 'icon'=>'flash', 'groups'=>array('video','web_video'), 'string'=>'video'),
@@ -1817,10 +1818,14 @@ function get_mimetype_description($obj, $capitalise=false) {
         $a[strtoupper($key)] = strtoupper($value);
         $a[ucfirst($key)] = ucfirst($value);
     }
-    if (get_string_manager()->string_exists($mimetype, 'mimetypes')) {
-        $result = get_string($mimetype, 'mimetypes', (object)$a);
-    } else if (get_string_manager()->string_exists($mimetypestr, 'mimetypes')) {
-        $result = get_string($mimetypestr, 'mimetypes', (object)$a);
+
+    // MIME types may include + symbol but this is not permitted in string ids.
+    $safemimetype = str_replace('+', '_', $mimetype);
+    $safemimetypestr = str_replace('+', '_', $mimetypestr);
+    if (get_string_manager()->string_exists($safemimetype, 'mimetypes')) {
+        $result = get_string($safemimetype, 'mimetypes', (object)$a);
+    } else if (get_string_manager()->string_exists($safemimetypestr, 'mimetypes')) {
+        $result = get_string($safemimetypestr, 'mimetypes', (object)$a);
     } else if (get_string_manager()->string_exists('default', 'mimetypes')) {
         $result = get_string('default', 'mimetypes', (object)$a);
     } else {
index 23f65cb..c81dfb7 100644 (file)
@@ -1279,6 +1279,9 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
     /** @var bool Whether to display advanced elements (on page load) */
     var $_showAdvanced = null;
 
+    /** @var bool whether to automatically initialise M.formchangechecker for this form. */
+    protected $_use_form_change_checker = true;
+
     /**
      * The form name is derived from the class name of the wrapper minus the trailing form
      * It is a name with words joined by underscores whereas the id attribute is words joined by underscores.
@@ -1406,8 +1409,32 @@ class MoodleQuickForm extends HTML_QuickForm_DHTMLRulesTableless {
         return $this->_showAdvanced;
     }
 
+    /**
+     * Call this method if you don't want the formchangechecker JavaScript to be
+     * automatically initialised for this form.
+     */
+    public function disable_form_change_checker() {
+        $this->_use_form_change_checker = false;
+    }
 
-   /**
+    /**
+     * If you have called {@link disable_form_change_checker()} then you can use
+     * this method to re-enable it. It is enabled by default, so normally you don't
+     * need to call this.
+     */
+    public function enable_form_change_checker() {
+        $this->_use_form_change_checker = true;
+    }
+
+    /**
+     * @return bool whether this form should automatically initialise
+     *      formchangechecker for itself.
+     */
+    public function is_form_change_checker_enabled() {
+        return $this->_use_form_change_checker;
+    }
+
+    /**
     * Accepts a renderer
     *
     * @param HTML_QuickForm_Renderer $renderer An HTML_QuickForm_Renderer object
@@ -2312,13 +2339,15 @@ class MoodleQuickForm_Renderer extends HTML_QuickForm_Renderer_Tableless{
             $this->_hiddenHtml .= $form->_pageparams;
         }
 
-        $PAGE->requires->yui_module('moodle-core-formchangechecker',
-                'M.core_formchangechecker.init',
-                array(array(
-                    'formid' => $form->getAttribute('id')
-                ))
-        );
-        $PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
+        if ($form->is_form_change_checker_enabled()) {
+            $PAGE->requires->yui_module('moodle-core-formchangechecker',
+                    'M.core_formchangechecker.init',
+                    array(array(
+                        'formid' => $form->getAttribute('id')
+                    ))
+            );
+            $PAGE->requires->string_for_js('changesmadereallygoaway', 'moodle');
+        }
     }
 
     /**
index 95b99f8..3fa19ec 100644 (file)
@@ -911,7 +911,10 @@ class grade_category extends grade_object {
 
                 $i = 1;
                 while ($originalindex+$i < count($grade_keys)) {
+
                     $possibleitemid = $grade_keys[$originalindex+$i];
+                    $i++;
+
                     if ($grade_values[$founditemid] != $grade_values[$possibleitemid]) {
                         // The next grade item has a different grade. Stop looking.
                         break;
@@ -928,8 +931,6 @@ class grade_category extends grade_object {
                         $founditemid = $possibleitemid;
                         // Continue searching to see if there is an even higher grademax...
                     }
-
-                    $i++;
                 }
 
                 // Now drop whatever grade item we have found
index 727e698..e4281a0 100644 (file)
@@ -516,6 +516,21 @@ class grade_category_testcase extends grade_base_testcase {
         $this->assertEquals(count($grades), 1);
         $this->assertEquals($grades[$this->grade_items[2]->id], 6);
 
+        // MDL-35667 - There was an infinite loop if several items had the same grade and at least one was extra credit
+        $category = new grade_category();
+        $category->droplow     = 1;
+        $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2; // simple weighted mean
+        $items[$this->grade_items[1]->id]->aggregationcoef = 1; // Mark grade item 1 as "extra credit"
+        $grades = array($this->grade_items[0]->id=>1, // 1 out of 110. Should be excluded from aggregation.
+                        $this->grade_items[1]->id=>1, // 1 out of 100. Extra credit. Should be retained.
+                        $this->grade_items[2]->id=>1, // 1 out of 6. Should be retained.
+                        $this->grade_items[4]->id=>1);// 1 out of 100. Should be retained.
+        $category->apply_limit_rules($grades, $items);
+        $this->assertEquals(count($grades), 3);
+        $this->assertEquals($grades[$this->grade_items[1]->id], 1);
+        $this->assertEquals($grades[$this->grade_items[2]->id], 1);
+        $this->assertEquals($grades[$this->grade_items[4]->id], 1);
+
     }
 
     /**
index b24c112..9ba6f13 100644 (file)
@@ -1197,7 +1197,7 @@ class global_navigation extends navigation_node {
                 break;
             case CONTEXT_COURSECAT :
                 // This has already been loaded we just need to map the variable
-                if ($showcategories) {
+                if ($this->show_categories()) {
                     $this->load_all_categories($this->page->context->instanceid, true);
                 }
                 break;
index b580259..f9dc68d 100644 (file)
@@ -544,6 +544,9 @@ class phpunit_util {
     public static function reset_all_data($logchanges = false) {
         global $DB, $CFG, $USER, $SITE, $COURSE, $PAGE, $OUTPUT, $SESSION, $GROUPLIB_CACHE;
 
+        // Release memory and indirectly call destroy() methods to release resource handles, etc.
+        gc_collect_cycles();
+
         // reset global $DB in case somebody mocked it
         $DB = self::get_global_backup('DB');
 
@@ -618,6 +621,10 @@ class phpunit_util {
         $GROUPLIB_CACHE = null;
         //TODO MDL-25290: add more resets here and probably refactor them to new core function
 
+        // Reset course and module caches.
+        $reset = 'reset';
+        get_fast_modinfo($reset);
+
         // purge dataroot directory
         self::reset_dataroot();
 
index 3e6e54b..b24f4fa 100644 (file)
@@ -44,16 +44,17 @@ class mod_assign_grading_options_form extends moodleform {
     function definition() {
         $mform = $this->_form;
         $instance = $this->_customdata;
+        $dirtyclass = array('class'=>'ignoredirty');
 
         $mform->addElement('header', 'general', get_string('gradingoptions', 'assign'));
         // visible elements
         $options = array(-1=>get_string('all'),10=>'10', 20=>'20', 50=>'50', 100=>'100');
-        $mform->addElement('select', 'perpage', get_string('assignmentsperpage', 'assign'), $options);
+        $mform->addElement('select', 'perpage', get_string('assignmentsperpage', 'assign'), $options, $dirtyclass);
         $options = array('' => get_string('filternone', 'assign'),
                          ASSIGN_FILTER_SUBMITTED => get_string('filtersubmitted', 'assign'),
                          ASSIGN_FILTER_REQUIRE_GRADING => get_string('filterrequiregrading', 'assign'));
         if ($instance['submissionsenabled']) {
-            $mform->addElement('select', 'filter', get_string('filter', 'assign'), $options);
+            $mform->addElement('select', 'filter', get_string('filter', 'assign'), $options, $dirtyclass);
         }
 
         // quickgrading
index 96c1c22..f362421 100644 (file)
@@ -78,6 +78,7 @@ $string['couldnotfindassignmenttoupgrade'] = 'Could not find old assignment inst
 $string['currentgrade'] = 'Current grade in gradebook';
 $string['defaultplugins'] = 'Default assignment settings';
 $string['defaultplugins_help'] = 'These settings define the defaults for all new assignments.';
+$string['deleteallsubmissions'] = 'Delete all submissions';
 $string['deletepluginareyousure'] = 'Delete assignment plugin {$a}: are you sure?';
 $string['deletepluginareyousuremessage'] = 'You are about to completely delete the assignment plugin {$a}. This will completely delete everything in the database associated with this assignment plugin. Are you SURE you want to continue?';
 $string['deletingplugin'] = 'Deleting plugin {$a}.';
index 74cfd3b..92490ec 100644 (file)
@@ -54,6 +54,72 @@ function assign_delete_instance($id) {
     return $assignment->delete_instance();
 }
 
+/**
+ * This function is used by the reset_course_userdata function in moodlelib.
+ * This function will remove all assignment submissions and feedbacks in the database
+ * and clean up any related data.
+ * @param $data the data submitted from the reset course.
+ * @return array status array
+ */
+function assign_reset_userdata($data) {
+    global $CFG, $DB;
+    require_once($CFG->dirroot . '/mod/assign/locallib.php');
+
+    $status = array();
+    $params = array('courseid'=>$data->courseid);
+    $sql = "SELECT a.id FROM {assign} a WHERE a.course=:courseid";
+    $course = $DB->get_record('course', array('id'=> $data->courseid), '*', MUST_EXIST);
+    if ($assigns = $DB->get_records_sql($sql,$params)) {
+        foreach ($assigns as $assign) {
+            $cm = get_coursemodule_from_instance('assign', $assign->id, $data->courseid, false, MUST_EXIST);
+            $context = context_module::instance($cm->id);
+            $assignment = new assign($context, $cm, $course);
+            $status = array_merge($status, $assignment->reset_userdata($data));
+        }
+    }
+    return $status;
+}
+
+/**
+ * Removes all grades from gradebook
+ *
+ * @param int $courseid The ID of the course to reset
+ * @param string $type Optional type of assignment to limit the reset to a particular assignment type
+ */
+function assign_reset_gradebook($courseid, $type='') {
+    global $CFG, $DB;
+
+    $params = array('moduletype'=>'assign','courseid'=>$courseid);
+    $sql = 'SELECT a.*, cm.idnumber as cmidnumber, a.course as courseid
+            FROM {assign} a, {course_modules} cm, {modules} m
+            WHERE m.name=:moduletype AND m.id=cm.module AND cm.instance=a.id AND a.course=:courseid';
+
+    if ($assignments = $DB->get_records_sql($sql,$params)) {
+        foreach ($assignments as $assignment) {
+            assign_grade_item_update($assignment, 'reset');
+        }
+    }
+}
+
+/**
+ * Implementation of the function for printing the form elements that control
+ * whether the course reset functionality affects the assignment.
+ * @param $mform form passed by reference
+ */
+function assign_reset_course_form_definition(&$mform) {
+    $mform->addElement('header', 'assignheader', get_string('modulenameplural', 'assign'));
+    $mform->addElement('advcheckbox', 'reset_assign_submissions', get_string('deleteallsubmissions','assign'));
+}
+
+/**
+ * Course reset form defaults.
+ * @param  object $course
+ * @return array
+ */
+function assign_reset_course_form_defaults($course) {
+    return array('reset_assign_submissions'=>1);
+}
+
 /**
  * Update an assignment instance
  *
index 8ba72d4..7238b70 100644 (file)
@@ -505,6 +505,82 @@ class assign {
         return $result;
     }
 
+    /**
+    * Actual implementation of the reset course functionality, delete all the
+    * assignment submissions for course $data->courseid.
+    *
+    * @param $data the data submitted from the reset course.
+    * @return array status array
+    */
+    public function reset_userdata($data) {
+        global $CFG,$DB;
+
+        $componentstr = get_string('modulenameplural', 'assign');
+        $status = array();
+
+        $fs = get_file_storage();
+        if (!empty($data->reset_assign_submissions)) {
+            // Delete files associated with this assignment.
+            foreach ($this->submissionplugins as $plugin) {
+                $fileareas = array();
+                $plugincomponent = $plugin->get_subtype() . '_' . $plugin->get_type();
+                $fileareas = $plugin->get_file_areas();
+                foreach ($fileareas as $filearea) {
+                    $fs->delete_area_files($this->context->id, $plugincomponent, $filearea);
+                }
+
+                if (!$plugin->delete_instance()) {
+                    $status[] = array('component'=>$componentstr,
+                                      'item'=>get_string('deleteallsubmissions','assign'),
+                                      'error'=>$plugin->get_error());
+                }
+            }
+
+            foreach ($this->feedbackplugins as $plugin) {
+                $fileareas = array();
+                $plugincomponent = $plugin->get_subtype() . '_' . $plugin->get_type();
+                $fileareas = $plugin->get_file_areas();
+                foreach ($fileareas as $filearea) {
+                    $fs->delete_area_files($this->context->id, $plugincomponent, $filearea);
+                }
+
+                if (!$plugin->delete_instance()) {
+                    $status[] = array('component'=>$componentstr,
+                                      'item'=>get_string('deleteallsubmissions','assign'),
+                                      'error'=>$plugin->get_error());
+                }
+            }
+
+            $assignssql = "SELECT a.id
+                             FROM {assign} a
+                           WHERE a.course=:course";
+            $params = array ("course" => $data->courseid);
+
+            $DB->delete_records_select('assign_submission', "assignment IN ($assignssql)", $params);
+            $status[] = array('component'=>$componentstr,
+                              'item'=>get_string('deleteallsubmissions','assign'),
+                              'error'=>false);
+
+            if (empty($data->reset_gradebook_grades)) {
+                // Remove all grades from gradebook.
+                require_once($CFG->dirroot.'/mod/assign/lib.php');
+                assign_reset_gradebook($data->courseid);
+            }
+        }
+        // Updating dates - shift may be negative too.
+        if ($data->timeshift) {
+            shift_course_mod_dates('assign',
+                                    array('duedate', 'allowsubmissionsfromdate'),
+                                    $data->timeshift,
+                                    $data->courseid);
+            $status[] = array('component'=>$componentstr,
+                              'item'=>get_string('datechanged'),
+                              'error'=>false);
+        }
+
+        return $status;
+    }
+
     /**
      * Update the settings for a single plugin
      *
index 470e18e..e15de10 100644 (file)
@@ -47,6 +47,7 @@ $string['editingchapter'] = 'Editing chapter';
 $string['chaptertitle'] = 'Chapter title';
 $string['content'] = 'Content';
 $string['subchapter'] = 'Subchapter';
+$string['nocontent'] = 'No content has been added to this book yet.';
 $string['numbering'] = 'Chapter formatting';
 $string['numbering_help'] = '* None - Chapter and subchapter titles have no formatting
 * Numbers - Chapters and subchapter titles are numbered 1, 1.1, 1.2, 2, ...
index eaae261..25ee6f7 100644 (file)
@@ -60,9 +60,9 @@ $mform = new booktool_importhtml_form(null, array('id'=>$id, 'chapterid'=>$chapt
 // If data submitted, then process and store.
 if ($mform->is_cancelled()) {
     if (empty($chapter->id)) {
-        redirect("/mod/book/view.php?id=$cm->id");
+        redirect($CFG->wwwroot."/mod/book/view.php?id=$cm->id");
     } else {
-        redirect("/mod/book/view.php?id=$cm->id&chapterid=$chapter->id");
+        redirect($CFG->wwwroot."/mod/book/view.php?id=$cm->id&chapterid=$chapter->id");
     }
 
 } else if ($data = $mform->get_data()) {
index 91b83b8..6b9365d 100644 (file)
@@ -87,13 +87,16 @@ if ($chapterid == '0') { // Go to first chapter if no given.
     }
 }
 
-if (!$chapterid or !$chapter = $DB->get_record('book_chapters', array('id'=>$chapterid, 'bookid'=>$book->id))) {
-    print_error('errorchapter', 'mod_book', new moodle_url('/course/view.php', array('id'=>$course->id)));
-}
+$courseurl = new moodle_url('/course/view.php', array('id' => $course->id));
 
-// chapter is hidden for students
-if ($chapter->hidden and !$viewhidden) {
-    print_error('errorchapter', 'mod_book', new moodle_url('/course/view.php', array('id'=>$course->id)));
+// No content in the book.
+if (!$chapterid) {
+    $PAGE->set_url('/mod/book/view.php', array('id' => $id));
+    notice(get_string('nocontent', 'mod_book'), $courseurl->out(false));
+}
+// Chapter doesnt exist or it is hidden for students
+if ((!$chapter = $DB->get_record('book_chapters', array('id' => $chapterid, 'bookid' => $book->id))) or ($chapter->hidden and !$viewhidden)) {
+    print_error('errorchapter', 'mod_book', $courseurl);
 }
 
 $PAGE->set_url('/mod/book/view.php', array('id'=>$id, 'chapterid'=>$chapterid));
index fc26f78..583ea73 100644 (file)
@@ -3408,21 +3408,28 @@ function data_page_type_list($pagetype, $parentcontext, $currentcontext) {
 /**
  * Get all of the record ids from a database activity.
  *
- * @param int $dataid      The dataid of the database module.
- * @return array $idarray  An array of record ids
+ * @param int    $dataid      The dataid of the database module.
+ * @param object $selectdata  Contains an additional sql statement for the
+ *                            where clause for group and approval fields.
+ * @param array  $params      Parameters that coincide with the sql statement.
+ * @return array $idarray     An array of record ids
  */
-function data_get_all_recordids($dataid) {
+function data_get_all_recordids($dataid, $selectdata = '', $params = null) {
     global $DB;
-    $initsql = 'SELECT c.recordid
-                  FROM {data_fields} f,
-                       {data_content} c
-                 WHERE f.dataid = :dataid
-                   AND f.id = c.fieldid
-              GROUP BY c.recordid';
-    $initrecord = $DB->get_recordset_sql($initsql, array('dataid' => $dataid));
+    $initsql = 'SELECT r.id
+                  FROM {data_records} r
+                 WHERE r.dataid = :dataid';
+    if ($selectdata != '') {
+        $initsql .= $selectdata;
+        $params = array_merge(array('dataid' => $dataid), $params);
+    } else {
+        $params = array('dataid' => $dataid);
+    }
+    $initsql .= ' GROUP BY r.id';
+    $initrecord = $DB->get_recordset_sql($initsql, $params);
     $idarray = array();
     foreach ($initrecord as $data) {
-        $idarray[] = $data->recordid;
+        $idarray[] = $data->id;
     }
     // Close the record set and free up resources.
     $initrecord->close();
@@ -3567,8 +3574,7 @@ function data_get_advanced_search_sql($sort, $data, $recordids, $selectdata, $so
     } else {
         list($insql, $inparam) = $DB->get_in_or_equal(array('-1'), SQL_PARAMS_NAMED);
     }
-    $nestfromsql .= ' AND c.recordid ' . $insql . $groupsql;
-    $nestfromsql = "$nestfromsql $selectdata";
+    $nestfromsql .= ' AND c.recordid ' . $insql . $selectdata . $groupsql;
     $sqlselect['sql'] = "$nestselectsql $nestfromsql $sortorder";
     $sqlselect['params'] = $inparam;
     return $sqlselect;
index 5ffa5bf..f740429 100644 (file)
 id,userid,groupid,dataid,timecreated,timemodified,approved
 1,1,0,1,1234567891,1234567892,1
-2,2,0,1,1234567891,1234567892,1
-3,3,0,1,1234567891,1234567892,1
-4,4,0,1,1234567891,1234567892,1
-5,5,0,1,1234567891,1234567892,1
-6,6,0,1,1234567891,1234567892,1
+2,2,1,1,1234567891,1234567892,1
+3,3,2,1,1234567891,1234567892,1
+4,4,1,1,1234567891,1234567892,1
+5,5,1,1,1234567891,1234567892,1
+6,6,2,1,1234567891,1234567892,1
 7,7,0,1,1234567891,1234567892,1
-8,8,0,1,1234567891,1234567892,1
-9,9,0,1,1234567891,1234567892,1
-10,10,0,1,1234567891,1234567892,1
-11,11,0,1,1234567891,1234567892,1
-12,12,0,1,1234567891,1234567892,1
-13,13,0,1,1234567891,1234567892,1
+8,8,2,1,1234567891,1234567892,1
+9,9,1,1,1234567891,1234567892,1
+10,10,1,1,1234567891,1234567892,1
+11,11,1,1,1234567891,1234567892,1
+12,12,2,1,1234567891,1234567892,1
+13,13,2,1,1234567891,1234567892,1
 14,14,0,1,1234567891,1234567892,1
-15,15,0,1,1234567891,1234567892,1
+15,15,2,1,1234567891,1234567892,1
 16,16,0,1,1234567891,1234567892,1
-17,17,0,1,1234567891,1234567892,1
-18,18,0,1,1234567891,1234567892,1
+17,17,1,1,1234567891,1234567892,1
+18,18,2,1,1234567891,1234567892,1
 19,19,0,1,1234567891,1234567892,1
-20,20,0,1,1234567891,1234567892,1
+20,20,1,1,1234567891,1234567892,1
 21,21,0,1,1234567891,1234567892,1
-22,22,0,1,1234567891,1234567892,1
+22,22,2,1,1234567891,1234567892,1
 23,23,0,1,1234567891,1234567892,1
-24,24,0,1,1234567891,1234567892,1
-25,25,0,1,1234567891,1234567892,1
+24,24,2,1,1234567891,1234567892,1
+25,25,2,1,1234567891,1234567892,1
 26,26,0,1,1234567891,1234567892,1
-27,27,0,1,1234567891,1234567892,1
-28,28,0,1,1234567891,1234567892,1
+27,27,1,1,1234567891,1234567892,1
+28,28,2,1,1234567891,1234567892,1
 29,29,0,1,1234567891,1234567892,1
-30,30,0,1,1234567891,1234567892,1
+30,30,2,1,1234567891,1234567892,1
 31,31,0,1,1234567891,1234567892,1
-32,32,0,1,1234567891,1234567892,1
-33,33,0,1,1234567891,1234567892,1
-34,34,0,1,1234567891,1234567892,1
-35,35,0,1,1234567891,1234567892,1
+32,32,1,1,1234567891,1234567892,1
+33,33,1,1,1234567891,1234567892,1
+34,34,2,1,1234567891,1234567892,1
+35,35,1,1,1234567891,1234567892,1
 36,36,0,1,1234567891,1234567892,1
 37,37,0,1,1234567891,1234567892,1
-38,38,0,1,1234567891,1234567892,1
-39,39,0,1,1234567891,1234567892,1
-40,40,0,1,1234567891,1234567892,1
+38,38,2,1,1234567891,1234567892,1
+39,39,1,1,1234567891,1234567892,1
+40,40,1,1,1234567891,1234567892,1
 41,41,0,1,1234567891,1234567892,1
-42,42,0,1,1234567891,1234567892,1
+42,42,1,1,1234567891,1234567892,1
 43,43,0,1,1234567891,1234567892,1
-44,44,0,1,1234567891,1234567892,1
+44,44,1,1,1234567891,1234567892,1
 45,45,0,1,1234567891,1234567892,1
 46,46,0,1,1234567891,1234567892,1
-47,47,0,1,1234567891,1234567892,1
+47,47,1,1,1234567891,1234567892,1
 48,48,0,1,1234567891,1234567892,1
 49,49,0,1,1234567891,1234567892,1
-50,50,0,1,1234567891,1234567892,1
+50,50,1,1,1234567891,1234567892,1
 51,51,0,1,1234567891,1234567892,1
 52,52,0,1,1234567891,1234567892,1
-53,53,0,1,1234567891,1234567892,1
-54,54,0,1,1234567891,1234567892,1
+53,53,1,1,1234567891,1234567892,1
+54,54,1,1,1234567891,1234567892,1
 55,55,0,1,1234567891,1234567892,1
-56,56,0,1,1234567891,1234567892,1
-57,57,0,1,1234567891,1234567892,1
-58,58,0,1,1234567891,1234567892,1
-59,59,0,1,1234567891,1234567892,1
-60,60,0,1,1234567891,1234567892,1
+56,56,2,1,1234567891,1234567892,1
+57,57,2,1,1234567891,1234567892,1
+58,58,2,1,1234567891,1234567892,1
+59,59,1,1,1234567891,1234567892,1
+60,60,1,1,1234567891,1234567892,1
 61,61,0,1,1234567891,1234567892,1
-62,62,0,1,1234567891,1234567892,1
+62,62,2,1,1234567891,1234567892,1
 63,63,0,1,1234567891,1234567892,1
 64,64,0,1,1234567891,1234567892,1
-65,65,0,1,1234567891,1234567892,1
-66,66,0,1,1234567891,1234567892,1
+65,65,1,1,1234567891,1234567892,1
+66,66,1,1,1234567891,1234567892,1
 67,67,0,1,1234567891,1234567892,1
 68,68,0,1,1234567891,1234567892,1
-69,69,0,1,1234567891,1234567892,1
-70,70,0,1,1234567891,1234567892,1
+69,69,2,1,1234567891,1234567892,1
+70,70,2,1,1234567891,1234567892,1
 71,71,0,1,1234567891,1234567892,1
-72,72,0,1,1234567891,1234567892,1
-73,73,0,1,1234567891,1234567892,1
+72,72,1,1,1234567891,1234567892,1
+73,73,1,1,1234567891,1234567892,1
 74,74,0,1,1234567891,1234567892,1
 75,75,0,1,1234567891,1234567892,1
-76,76,0,1,1234567891,1234567892,1
-77,77,0,1,1234567891,1234567892,1
+76,76,2,1,1234567891,1234567892,1
+77,77,2,1,1234567891,1234567892,1
 78,78,0,1,1234567891,1234567892,1
-79,79,0,1,1234567891,1234567892,1
-80,80,0,1,1234567891,1234567892,1
+79,79,1,1,1234567891,1234567892,1
+80,80,1,1,1234567891,1234567892,1
 81,81,0,1,1234567891,1234567892,1
-82,82,0,1,1234567891,1234567892,1
-83,83,0,1,1234567891,1234567892,1
-84,84,0,1,1234567891,1234567892,1
-85,85,0,1,1234567891,1234567892,1
+82,82,1,1,1234567891,1234567892,1
+83,83,1,1,1234567891,1234567892,1
+84,84,1,1,1234567891,1234567892,1
+85,85,1,1,1234567891,1234567892,1
 86,86,0,1,1234567891,1234567892,1
 87,87,0,1,1234567891,1234567892,1
 88,88,0,1,1234567891,1234567892,1
-89,89,0,1,1234567891,1234567892,1
-90,90,0,1,1234567891,1234567892,1
-91,91,0,1,1234567891,1234567892,1
-92,92,0,1,1234567891,1234567892,1
-93,93,0,1,1234567891,1234567892,1
-94,94,0,1,1234567891,1234567892,1
-95,95,0,1,1234567891,1234567892,1
-96,96,0,1,1234567891,1234567892,1
-97,97,0,1,1234567891,1234567892,1
-98,98,0,1,1234567891,1234567892,1
-99,99,0,1,1234567891,1234567892,1
-100,100,0,1,1234567891,1234567892,1
+89,89,1,1,1234567891,1234567892,1
+90,90,1,1,1234567891,1234567892,0
+91,91,2,1,1234567891,1234567892,0
+92,92,0,1,1234567891,1234567892,0
+93,93,2,1,1234567891,1234567892,0
+94,94,1,1,1234567891,1234567892,0
+95,95,1,1,1234567891,1234567892,0
+96,96,1,1,1234567891,1234567892,0
+97,97,0,1,1234567891,1234567892,0
+98,98,1,1,1234567891,1234567892,0
+99,99,2,1,1234567891,1234567892,0
+100,100,0,1,1234567891,1234567892,0
index 150bc5d..2980643 100644 (file)
@@ -70,6 +70,11 @@ class data_advanced_search_sql_test extends advanced_testcase {
      */
     public $datarecordcount = 100;
 
+    /**
+     * @var int $groupdatarecordcount  The number of records in the database in groups 0 and 1.
+     */
+    public $groupdatarecordcount = 75;
+
     /**
      * @var array $datarecordset   Expected record IDs.
      */
@@ -80,6 +85,11 @@ class data_advanced_search_sql_test extends advanced_testcase {
      */
     public $finalrecord = array();
 
+    /**
+     * @var int $approvedatarecordcount  The number of approved records in the database.
+     */
+    public $approvedatarecordcount = 89;
+
     /**
      * Set up function. In this instance we are setting up database
      * records to be used in the unit tests.
@@ -169,6 +179,13 @@ class data_advanced_search_sql_test extends advanced_testcase {
      * Test 4: data_get_advanced_search_sql provides an array which contains an sql string to be used for displaying records
      * to the user when they use the advanced search criteria and the parameters that go with the sql statement. This test
      * takes that information and does a search on the database, returning a record.
+     *
+     * Test 5: Returning to data_get_all_recordids(). Here we are ensuring that the total amount of record ids is reduced to
+     * match the group conditions that are provided. There are 25 entries which relate to group 2. They are removed
+     * from the total so we should only have 75 records total.
+     *
+     * Test 6: data_get_all_recordids() again. This time we are testing approved database records. We only want to
+     * display the records that have been approved. In this record set we have 89 approved records.
      */
     function test_advanced_search_sql_section() {
         global $DB;
@@ -193,5 +210,16 @@ class data_advanced_search_sql_test extends advanced_testcase {
         $allparams = array_merge($html['params'], array('dataid' => $this->recorddata->id));
         $records = $DB->get_records_sql($html['sql'], $allparams);
         $this->assertEquals($records, $this->finalrecord);
+
+        // Test 5
+        $groupsql = " AND (r.groupid = :currentgroup OR r.groupid = 0)";
+        $params = array('currentgroup' => 1);
+        $recordids = data_get_all_recordids($this->recorddata->id, $groupsql, $params);
+        $this->assertEquals($this->groupdatarecordcount, count($recordids));
+
+        // Test 6
+        $approvesql = ' AND r.approved=1 ';
+        $recordids = data_get_all_recordids($this->recorddata->id, $approvesql, $params);
+        $this->assertEquals($this->approvedatarecordcount, count($recordids));
     }
 }
index 3e9146e..1b2d85b 100644 (file)
     groups_print_activity_menu($cm, $returnurl);
     $currentgroup = groups_get_activity_group($cm);
     $groupmode = groups_get_activity_groupmode($cm);
+    // If a student is not part of a group and seperate groups is enabled, we don't
+    // want them seeing all records.
+    if ($currentgroup == 0 && $groupmode == 1 && !has_capability('mod/data:manageentries', $context)) {
+        $canviewallrecords = false;
+    } else {
+        $canviewallrecords = true;
+    }
 
     // detect entries not approved yet and show hint instead of not found error
     if ($record and $data->approval and !$record->approved and $record->userid != $USER->id and !has_capability('mod/data:manageentries', $context)) {
@@ -465,7 +472,13 @@ if ($showactivity) {
             $groupselect = " AND (r.groupid = :currentgroup OR r.groupid = 0)";
             $params['currentgroup'] = $currentgroup;
         } else {
-            $groupselect = ' ';
+            if ($canviewallrecords) {
+                $groupselect = ' ';
+            } else {
+                // If separate groups are enabled and the user isn't in a group or
+                // a teacher, manager, admin etc, then just show them entries for 'All participants'.
+                $groupselect = " AND r.groupid = 0";
+            }
         }
 
         // Init some variables to be used by advanced search
@@ -590,10 +603,19 @@ if ($showactivity) {
         $sqlmax     = "SELECT $count FROM $tables $where $groupselect $approveselect"; // number of all recoirds user may see
         $allparams  = array_merge($params, $advparams);
 
-        $recordids = data_get_all_recordids($data->id);
+        // Provide initial sql statements and parameters to reduce the number of total records.
+        $selectdata = $groupselect . $approveselect;
+        $initialparams = array();
+        if ($currentgroup) {
+            $initialparams['currentgroup'] = $params['currentgroup'];
+        }
+        if (!$approvecap && $data->approval && isloggedin()) {
+            $initialparams['myid1'] = $params['myid1'];
+        }
+
+        $recordids = data_get_all_recordids($data->id, $selectdata, $initialparams);
         $newrecordids = data_get_advance_search_ids($recordids, $search_array, $data->id);
         $totalcount = count($newrecordids);
-        $selectdata = $groupselect . $approveselect;
 
         if (!empty($advanced)) {
             $advancedsearchsql = data_get_advanced_search_sql($sort, $data, $newrecordids, $selectdata, $sortorder);
index 3ab0f5a..322ccdd 100644 (file)
@@ -116,6 +116,7 @@ table.quizattemptsummary .noreviewmessage {color: gray;}
 #page-mod-quiz-view .generalbox#feedback {width:70%;margin-left:auto;margin-right:auto;padding-bottom:15px;}
 #page-mod-quiz-view .generalbox#feedback h2 {margin: 0;}
 #page-mod-quiz-view .generalbox#feedback h3 {text-align: left;}
+#page-mod-quiz-view.dir-rtl .generalbox#feedback h3 {text-align: center;}
 #page-mod-quiz-view .generalbox#feedback .overriddennotice {text-align: center;font-size: 0.7em;}
 .quizstartbuttondiv.quizsecuremoderequired input { display: none; }
 .jsenabled .quizstartbuttondiv.quizsecuremoderequired input { display: inline; }
@@ -251,6 +252,7 @@ table#categoryquestions {width: 100%;overflow: hidden;table-layout: fixed;}
 #page-mod-quiz-edit div.question div.content .singlequestion .questiontext{display:inline-block;}
 #page-mod-quiz-edit div.question div.content .singlequestion .questionpreview{background-color:#eee;}
 #page-mod-quiz-edit div.question div.content .questiontype{display:block;clear:left;float:left;}
+#page-mod-quiz-edit.dir-rtl div.question div.content .questiontype {clear: right;float: right;}
 #page-mod-quiz-edit div.question div.content .questionpreview {display:block;float:left;margin-left:0.3em;padding-left:0.2em;padding-right:0.2em;}
 #page-mod-quiz-edit div.question div.content .questionpreview a{background-color:#eee;}
 #page-mod-quiz-edit div.question div.content div.quiz_randomquestion .questionpreview{display:inline;float:none;}
@@ -399,7 +401,7 @@ bank window's title is prominent enough*/
 #page-mod-quiz-edit.dir-rtl div.question {clear: right;}
 #page-mod-quiz-edit.dir-rtl div.question div.qnum {float: right;}
 #page-mod-quiz-edit.dir-rtl div.editq div.question div.content {float: right;height: 40px;}
-#page-mod-quiz-edit.dir-rtl div.question div.content div.points {left: 50px;right:auto;}
+#page-mod-quiz-edit.dir-rtl div.question div.content div.points {left: 5px;right:auto;}
 #page-mod-quiz-edit.dir-rtl div.question div.content div.questioncontrols {float: left;left: 0.3em; right:auto;}
 #page-mod-quiz-edit.dir-rtl .editq div.question div.content .singlequestion .questioneditbutton .questionname,
 #page-mod-quiz-edit.dir-rtl .editq div.question div.content .singlequestion .questioneditbutton .questiontext {float: right; padding-right: 0.3em;}
index 72411c8..6eac247 100644 (file)
@@ -21,6 +21,9 @@ optional - no changes needed:
   xxx_dndupload_register() and xxx_dndupload_handle($uploadinfo) see:
   http://docs.moodle.org/dev/Implementing_Course_drag_and_drop_upload_support_in_a_module
 
+* mod/data/lib.php data_get_all_recordids() now has two new optional variables:  $selectdata and $params.
+
+
 === 2.2 ===
 
 required changes in code:
@@ -29,12 +32,20 @@ required changes in code:
 * textlib->asort() replaced by specialized collatorlib::asort()
 * use new make_temp_directory() and make_cache_directory()
 
+optional - no changes needed:
+
+* mod/data/lib.php data_get_all_recordids() now has two new optional variables:  $selectdata and $params.
+
 
 === 2.1 ===
 
 required changes in code:
 * add new support for basic restore from 1.9
 
+optional - no changes needed:
+
+* mod/data/lib.php data_get_all_recordids() now has two new optional variables:  $selectdata and $params.
+
 
 === 2.0 ===
 
diff --git a/pix/f/epub.png b/pix/f/epub.png
new file mode 100644 (file)
index 0000000..a660c73
Binary files /dev/null and b/pix/f/epub.png differ
index beb3788..2fbe4e0 100644 (file)
@@ -27,7 +27,7 @@ M.qtype_multianswer = M.qtype_multianswer || {};
 
 
 M.qtype_multianswer.init = function (Y, questiondiv) {
-    Y.one(questiondiv).all('label.subq').each(function(subqspan, i) {
+    Y.one(questiondiv).all('span.subquestion').each(function(subqspan, i) {
         var feedbackspan = subqspan.one('.feedbackspan');
         if (!feedbackspan) {
             return;
index 0134eb4..5afe4ff 100644 (file)
@@ -227,12 +227,13 @@ class qtype_multianswer_textfield_renderer extends qtype_multianswer_subq_render
                         $qa, 'question', 'answerfeedback', $matchinganswer->id),
                 s($correctanswer->answer), $options);
 
-        $output = '';
+        $output = html_writer::start_tag('span', array('class' => 'subquestion'));
         $output .= html_writer::tag('label', get_string('answer'),
                 array('class' => 'subq accesshide', 'for' => $inputattributes['id']));
         $output .= html_writer::empty_tag('input', $inputattributes);
         $output .= $feedbackimg;
         $output .= $feedbackpopup;
+        $output .= html_writer::end_tag('span');
 
         return $output;
     }
@@ -294,12 +295,13 @@ class qtype_multianswer_multichoice_inline_renderer
                 $subq->format_text($rightanswer->answer, $rightanswer->answerformat,
                         $qa, 'question', 'answer', $rightanswer->id), $options);
 
-        $output = '';
+        $output = html_writer::start_tag('span', array('class' => 'subquestion'));
         $output .= html_writer::tag('label', get_string('answer'),
                 array('class' => 'subq accesshide', 'for' => $inputattributes['id']));
         $output .= $select;
         $output .= $feedbackimg;
         $output .= $feedbackpopup;
+        $output .= html_writer::end_tag('span');
 
         return $output;
     }
index 1d5664d..1a0210a 100644 (file)
@@ -34,4 +34,4 @@ $string['upload_error_no_file'] = 'No file was uploaded.';
 $string['upload_error_no_tmp_dir'] = 'PHP is missing a temporary folder.';
 $string['upload_error_cant_write'] = 'Failed to write file to disk.';
 $string['upload_error_extension'] = 'A PHP extension stopped the file upload.';
-$string['upload_error_invalid_file'] = 'The file \'{$a}\' has no data in it - did you try to upload a folder?';
\ No newline at end of file
+$string['upload_error_invalid_file'] = 'The file \'{$a}\' is either empty or a folder. To upload folders zip them first.';
\ No newline at end of file
index 3aec3d8..4a5151b 100644 (file)
@@ -905,6 +905,9 @@ sup {vertical-align: super;}
     -webkit-box-shadow: inset 0px 0px 30px 0px #CCCCCC;
     -moz-box-shadow: inset 0px 0px 30px 0px #CCCCCC;
 }
+.dir-rtl.jsenabled .choosercontainer #chooseform .alloptions {
+    max-width: 18.3em;
+}
 
 /* Settings for option rows and option subtypes */
 .choosercontainer #chooseform .moduletypetitle,
index cb80bc2..0b4746e 100644 (file)
@@ -67,7 +67,7 @@ $string['ctmo_onfrontpageonly'] = 'in the front page only'; // ctmo == credits t
 $string['customcss'] = 'Custom CSS';
 $string['customcssdesc'] = 'Any CSS you enter here will be added to every page allowing your to easily customise this theme.';
 $string['customlogourl'] = 'Custom logo';
-$string['customlogourldesc'] = 'Change the logo for this theme by entering the URL to an image you wish to use (i.e. http://www.yoursite.local/mylogo.png). As a reference the default logo is 200px wide, 50px high and a transparent png will work best.';
+$string['customlogourldesc'] = 'Change the logo for this theme by entering the full or relatve URL to an image you wish to use (i.e. http://www.yoursite.tld/mylogo.png or ../path/to/your/logo.png). As a reference the default logo is 200px wide, 50px high and a transparent png will work best.';
 $string['displayheading'] = 'Display page heading';
 $string['displaylogo'] = 'Display logo';
 $string['fontsizereference'] = 'Font size reference';
@@ -77,7 +77,7 @@ $string['footnotedesc'] = 'The content from this textarea will be displayed in t
 $string['framemargin'] = 'Frame margin';
 $string['framemargindesc'] = 'Room between the frame and the edge of the browser window. (This setting will be ignored if "{$a}" is requested).';
 $string['frontpagelogourl'] = 'Custom front page logo';
-$string['frontpagelogourldesc'] = 'Change the logo that is displayed on the front page of your site by entering the URL to the image you wish to use (i.e. http://www.yoursite.local/myfrontpagelogo.png). This setting overrides the custom logo setting. As a reference the default logo is 300px wide, 80px high and a transparent png will work best.';
+$string['frontpagelogourldesc'] = 'Change the logo that is displayed on the front page of your site by entering the full or relatve URL to the image you wish to use (i.e. http://www.yoursite.tld/myfrontpagelogo.png or ../path/to/your/logo.png). This setting overrides the custom logo setting. As a reference the default logo is 300px wide, 80px high and a transparent png will work best.';
 $string['headerbgc'] = 'Header background colour';
 $string['headerbgcdesc'] = 'This sets the blocks header background colour for the theme.';
 $string['headercontent'] = 'Header content';
index f57325a..31ea104 100644 (file)
@@ -16,34 +16,34 @@ html {
     background: none;
 }
 
-body,h1,h2,h3,h4,h5,h6,p,ul,ol,dl,input,textarea { 
+body,h1,h2,h3,h4,h5,h6,p,ul,ol,dl,input,textarea {
     font-family: Georgia, "Times New Roman", Times, serif;
     color: #2a2513;
 }
 
-#wrapper { 
+#wrapper {
     background: #fff;
     margin: 2% 5%;
     padding: 5px;
     border: 1px solid #c1bc9d;
 }
 
-a { 
+a {
     color: #336699;
 }
 
-a:hover { 
+a:hover {
     text-decoration: underline;
 }
 
-.pagelayout-frontpage #page-content #region-main-box #region-post-box { 
+.pagelayout-frontpage #page-content #region-main-box #region-post-box {
     padding-top: 0;
 }
 
 /* Header
 ------------------------*/
 
-#page-header { 
+#page-header {
     background: #ddd6cc url([[pix:theme|header_grass]]) repeat-x 0 100%;
     margin-bottom: 5px;
 }
@@ -52,7 +52,7 @@ a:hover {
     margin-bottom: 0px;
 }
 
-.headermain { 
+.headermain {
     font-weight: normal;
     margin: 1em 0.5em 0.75em;
 }
@@ -67,10 +67,10 @@ a:hover {
     float:none;
 }
 
-/* Navbar 
+/* Navbar
 -------------------------*/
 
-.navbar { 
+.navbar {
     background: #aeb9c6 url([[pix:theme|breadcrumb]]) repeat-x 0 100%;
     padding: 5px;
 }
@@ -78,21 +78,21 @@ a:hover {
 /* Blocks
 -------------------------*/
 
-.block { 
+.block {
     border-color: #eee;
 }
 
-.block .header { 
+.block .header {
     background: #9eb1bf;
     padding-left: 5px;
 }
 
-.block .title { 
+.block .title {
     background: #867f6a;
     padding-left: 5px;
 }
 
-.block .title h2 { 
+.block .title h2 {
     background: #6e6855;
     margin: 0;
     padding: 5px;
@@ -100,24 +100,24 @@ a:hover {
     color: #fff;
 }
 
-.block_action { 
+.block_action {
     padding: 5px 0 0;
 }
 
-.block .content { 
+.block .content {
     background: #d8d2c6;
     border: 1px solid #867f6a;
 }
 
 .block .minicalendar td,
-.block .minicalendar th { 
+.block .minicalendar th {
     border-color: #d8d2c6;
 }
 
 /* Course
 ----------------------------*/
 
-.headingblock { 
+.headingblock {
     background: url([[pix:theme|headingblock]]) repeat-x 0 0;
     color: #fff;
     font-weight: normal;
@@ -142,10 +142,10 @@ a:hover {
     background: #fff;
 }
 
-/* Forums 
+/* Forums
 -----------------------------*/
 
-.forumpost .topic { 
+.forumpost .topic {
     background: #cad5e1;
     border-width: 1px;
     border-color: #eee #eee #aaa;
@@ -158,11 +158,11 @@ a:hover {
 }
 
 
-.forumpost .starter .subject { 
+.forumpost .starter .subject {
     font-weight: bold;
 }
 
-.forumpost .content { 
+.forumpost .content {
     border-color: #eee;
     border-width: 0 1px 1px;
     border-style: solid;
@@ -172,56 +172,56 @@ a:hover {
 /* Dock
 -----------------------------*/
 
-body.has_dock { 
+body.has_dock {
     margin: 0;
 }
 
-#dock { 
+#dock {
     left: 5%;
     margin-left: -29px;
     border-width: 0;
     background-color: transparent;
 }
 
-#dock .controls { 
+#dock .controls {
     bottom: auto;
     background-color: #DDD6CC;
 }
 
-#dock .dockeditem_container { 
+#dock .dockeditem_container {
     position: relative;
 }
 
-#dock .dockeditem.firstdockitem { 
+#dock .dockeditem.firstdockitem {
     margin-top: 50px;
 }
 
-#dock .dockeditem { 
+#dock .dockeditem {
     background-color: #fff;
     padding: 2px;
     padding-right: 0px;
 }
 
-#dock .dockedtitle { 
+#dock .dockedtitle {
     border-width: 0;
 }
 
-#dock .dockedtitle h2 { 
+#dock .dockedtitle h2 {
     margin: 0;
     padding: 10px 3px;
 }
 
-#dock .dockedtitle.activeitem { 
+#dock .dockedtitle.activeitem {
     background-color: #817b65;
     width: 35px;
 }
 
-#dockeditempanel { 
+#dockeditempanel {
     background-color: #817b65;
     margin-left: 5px;
 }
 
-#dockeditempanel .dockeditempanel_content { 
+#dockeditempanel .dockeditempanel_content {
     background-color: #eee9e0;
     margin: 0 3px;
     position: relative;
@@ -230,78 +230,77 @@ body.has_dock {
     border-color: #6f6856;
 }
 
-#dockeditempanel .dockeditempanel_hd { 
+#dockeditempanel .dockeditempanel_hd {
     background-image: url([[pix:theme|headingblock]]);
     border-width: 0;
 }
 
-#dockeditempanel .dockeditempanel_hd h2 { 
+#dockeditempanel .dockeditempanel_hd h2 {
     font-size: 1em;
     color: #fff;
 }
 
 /*cutom menu */
 /*YUI Reset */
-.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-content,
-.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-label,
-.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-label-active,
-.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menuitem-active .yui3-menuitem-content,
-.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-label-menuvisible {background-position: -10000px -10000px;}
-.yui3-skin-sam #page .yui3-menu-label,
-.yui3-skin-sam #page .yui3-menu .yui3-menu .yui3-menu-label,
-.yui3-skin-sam #page .yui3-menubuttonnav .yui3-menu-label em {background-position: right center;}
-.yui3-skin-sam #page .yui3-splitbuttonnav .yui3-menu-label .yui3-menu-toggle {background-position: 3px center;}
-.yui3-skin-sam #page .yui3-splitbuttonnav .yui3-menu-label-menuvisible .yui3-menu-toggle {background-position: 0% 50%;}
-
+#custommenu .yui3-menu-horizontal .yui3-menu-content,
+#custommenu .yui3-menu-horizontal .yui3-menu-label,
+#custommenu .yui3-menu-horizontal .yui3-menu-label-active,
+#custommenu .yui3-menu-horizontal .yui3-menuitem-active .yui3-menuitem-content,
+#custommenu .yui3-menu-horizontal .yui3-menu-label-menuvisible {
+    background-position: -10000px -10000px;
+}
+#custommenu .yui3-menu-label,
+#custommenu .yui3-menu .yui3-menu .yui3-menu-label,
+#custommenu .yui3-menubuttonnav .yui3-menu-label em {
+    background-position: right center;
+}
+#custommenu .yui3-splitbuttonnav .yui3-menu-label .yui3-menu-toggle {
+    background-position: 3px center;
+}
+#custommenu .yui3-splitbuttonnav .yui3-menu-label-menuvisible .yui3-menu-toggle {
+    background-position: 0% 50%;
+}
 #custommenu {
     clear: both;
     background-image: url([[pix:theme|headingblock]]);
     margin-bottom: 5px;
 }
-
-.yui3-skin-sam #page .yui3-menu-label,
-.yui3-skin-sam #page .yui3-menuitem-content  {
+#custommenu .yui3-menu-label,
+#custommenu .yui3-menuitem-content {
     color: #fff;
     font-weight: 800;
     line-height: 30px;
 }
-
-.custom_menu_submenu .yui3-menu-label,
-.custom_menu_submenu .yui3-menuitem-content {
-    color: #000 !important;
-    text-shadow: none !important;
+#custommenu .custom_menu_submenu .yui3-menu-label,
+#custommenu .custom_menu_submenu .yui3-menuitem-content {
+    color: #333;
+    text-shadow: none;
     line-height: 25px;
 }
-
-.yui3-skin-sam #page .yui3-menu-label.yui3-menu-label-active,
-.yui3-skin-sam #page .yui3-menu-label.yui3-menu-label-menuvisible,
-.yui3-skin-sam #page .yui3-menuitem-active .yui3-menuitem-content {
+#custommenu .yui3-menu-label.yui3-menu-label-active,
+#custommenu .yui3-menu-label.yui3-menu-label-menuvisible,
+#custommenu .yui3-menuitem-active .yui3-menuitem-content {
     color: #000;
     background-color: #d8d2c6;
 }
-
-.yui3-skin-sam #page .yui3-menu-content,
-.yui3-skin-sam #page .yui3-menu-content,
-.yui3-skin-sam #page .yui3-menu .yui3-menu .yui3-menu-content,
-.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menu-label,
-.yui3-skin-sam #page .yui3-menu-horizontal .yui3-menuitem-content  {
-    border: none !important;
+#custommenu .yui3-menu-content,
+#custommenu .yui3-menu-content,
+#custommenu .yui3-menu .yui3-menu .yui3-menu-content,
+#custommenu .yui3-menu-horizontal .yui3-menu-label,
+#custommenu .yui3-menu-horizontal .yui3-menuitem-content  {
+    border: 0 none;
 }
-
-.yui3-skin-sam .yui3-menu-horizontal .yui3-menu-label,
-.yui3-skin-sam .yui3-menu-horizontal .yui3-menuitem-content {
-    border-color:#808080;
-    border-style:solid;
-    border-width:0px 0;
+#custommenu .yui3-menu-horizontal .yui3-menu-label,
+#custommenu .yui3-menu-horizontal .yui3-menuitem-content {
+    border: 0 none;
 }
-
-#page .custom_menu_submenu {
-    border: 2px solid #d8d2c6 !important;
+#custommenu .custom_menu_submenu {
+    border: 2px solid #d8d2c6;
     background: #fff;
-     -webkit-border-radius: 2px;
-    -moz-border-radius: 2px;
-    border-radius: 2px;
+    -webkit-border-radius: 2px;
+       -moz-border-radius: 2px;
+            border-radius: 2px;
     -webkit-box-shadow: 0px 1px 3px #ccc;
-    -moz-box-shadow: 0px 1px 3px #ccc;
-    box-shadow: 0px 1px 3px #ccc;
-}
\ No newline at end of file
+       -moz-box-shadow: 0px 1px 3px #ccc;
+            box-shadow: 0px 1px 3px #ccc;
+}
index de2f500..120fb78 100644 (file)
@@ -221,8 +221,9 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
 
             // Output each optgroup.
             var count = 0;
-            for (var groupname in data.results) {
-                this.output_group(groupname, data.results[groupname], selectedusers, true);
+            for (var key in data.results) {
+                var groupdata = data.results[key];
+                this.output_group(groupdata.name, groupdata.users, selectedusers, true);
                 count++;
             }
             if (!count) {
@@ -248,13 +249,14 @@ M.core_user.init_user_selector = function (Y, name, hash, extrafields, lastsearc
         output_group : function(groupname, users, selectedusers, processsingle) {
             var optgroup = Y.Node.create('<optgroup></optgroup>');
             var count = 0;
-            for (var userid in users) {
-                var user = users[userid];
-                var option = Y.Node.create('<option value="'+userid+'">'+user.name+'</option>');
+            for (var key in users) {
+                var user = users[key];
+                var option = Y.Node.create('<option value="'+user.id+'">'+user.name+'</option>');
                 if (user.disabled) {
                     option.set('disabled', true);
-                } else if (selectedusers===true || selectedusers[userid]) {
+                } else if (selectedusers===true || selectedusers[user.id]) {
                     option.set('selected', true);
+                    delete selectedusers[user.id];
                 } else {
                     option.set('selected', false);
                 }
index fcaf74e..ab28274 100644 (file)
@@ -78,17 +78,20 @@ if (isset($options['file'])) {
 $userselector = new $classname($name, $options);
 
 // Do the search and output the results.
-$users = $userselector->find_users($search);
-foreach ($users as &$group) {
-    foreach ($group as $user) {
+$results = $userselector->find_users($search);
+$json = array();
+foreach ($results as $groupname => $users) {
+    $groupdata = array('name' => $groupname, 'users' => array());
+    foreach ($users as $user) {
         $output = new stdClass;
         $output->id = $user->id;
         $output->name = $userselector->output_user($user);
         if (!empty($user->disabled)) {
             $output->disabled = true;
         }
-        $group[$user->id] = $output;
+        $groupdata['users'][] = $output;
     }
+    $json[] = $groupdata;
 }
 
-echo json_encode(array('results' => $users));
+echo json_encode(array('results' => $json));
index a5b0b9a..4fc7f14 100644 (file)
 defined('MOODLE_INTERNAL') || die();
 
 
-$version  = 2012062502.05;              // YYYYMMDD      = weekly release date of this DEV branch
+$version  = 2012062502.06;              // YYYYMMDD      = weekly release date of this DEV branch
                                         //         RR    = release increments - 00 in DEV branches
                                         //           .XX = incremental changes
 
-$release  = '2.3.2+ (Build: 20121005)'; // Human-friendly version name
+$release  = '2.3.2+ (Build: 20121014)'; // Human-friendly version name
 
 $branch   = '23';                       // this version's branch
 $maturity = MATURITY_STABLE;            // this version's maturity level