Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse code

Merge branch 'master' of git://github.com/moodle/moodle

  • Loading branch information...
commit 372a0cf82e0323694f68419f62a5fee2f088b238 2 parents c00207c + 216f6d8
kordan authored January 27, 2012

Showing 103 changed files with 8,078 additions and 2,927 deletions. Show diff stats Hide diff stats

  1. 4  admin/settings/subsystems.php
  2. 2  backup/util/helper/restore_decode_processor.class.php
  3. 2  backup/util/loggers/file_logger.class.php
  4. 7  blocks/navigation/renderer.php
  5. 2  calendar/lib.php
  6. 26  config-dist.php
  7. 4  course/format/topics/format.php
  8. 2  course/lib.php
  9. 44  enrol/externallib.php
  10. 2  grade/grading/lib.php
  11. 4  install/lang/de/install.php
  12. 3  install/lang/de_du/install.php
  13. 2  install/lang/de_kids/langconfig.php
  14. 3  install/lang/he/install.php
  15. 2  lang/en/admin.php
  16. 1  lang/en/error.php
  17. 4  lang/en/moodle.php
  18. 1  lang/en/question.php
  19. 3,584  lib/csslib.php
  20. 5  lib/enrollib.php
  21. 47  lib/form/dndupload.js
  22. 13  lib/form/filemanager.js
  23. 4  lib/form/filemanager.php
  24. 136  lib/moodlelib.php
  25. 31  lib/navigationlib.php
  26. 2  lib/outputcomponents.php
  27. 2  lib/outputrenderers.php
  28. 2  lib/portfoliolib.php
  29. 4  lib/simpletest/testcompletionlib.php
  30. 706  lib/simpletest/testcsslib.php
  31. 3  lib/simpletest/testfilterconfig.php
  32. 4,245  lib/timezone.txt
  33. 8  message/lib.php
  34. 7  mod/forum/lib.php
  35. 18  mod/glossary/lib.php
  36. 4  mod/quiz/locallib.php
  37. 2  mod/quiz/renderer.php
  38. 4  mod/quiz/report/reportlib.php
  39. 13  mod/resource/lang/en/resource.php
  40. 53  mod/resource/lib.php
  41. 72  mod/resource/locallib.php
  42. 21  mod/resource/mod_form.php
  43. 6  mod/resource/settings.php
  44. 4  mod/resource/styles.css
  45. 26  mod/workshop/form/rubric/backup/moodle1/lib.php
  46. 10  question/behaviour/adaptive/simpletest/testwalkthrough.php
  47. 2  question/behaviour/immediatecbm/simpletest/testwalkthrough.php
  48. 6  question/behaviour/interactive/simpletest/testwalkthrough.php
  49. 16  question/editlib.php
  50. 8  question/engine/questionattempt.php
  51. 1  question/engine/questionusage.php
  52. 23  question/engine/simpletest/helpers.php
  53. 4  question/preview.php
  54. 1  question/type/calculated/lang/en/qtype_calculated.php
  55. 36  question/type/calculated/questiontype.php
  56. 37  question/type/calculated/simpletest/helper.php
  57. 20  question/type/calculated/simpletest/testquestion.php
  58. 107  question/type/calculated/simpletest/testquestiontype.php
  59. 6  question/type/match/backup/moodle1/lib.php
  60. 7  question/type/numerical/question.php
  61. 11  question/type/numerical/questiontype.php
  62. 3  question/type/numerical/simpletest/helper.php
  63. 35  question/type/numerical/simpletest/testquestion.php
  64. 17  question/type/numerical/simpletest/testquestiontype.php
  65. 9  question/type/questionbase.php
  66. 20  question/type/questiontypebase.php
  67. 12  question/type/randomsamatch/lang/en/qtype_randomsamatch.php
  68. 10  question/type/shortanswer/questiontype.php
  69. 133  question/type/shortanswer/simpletest/helper.php
  70. 31  question/type/shortanswer/simpletest/testquestion.php
  71. 33  question/type/shortanswer/simpletest/testquestiontype.php
  72. 2  question/type/truefalse/simpletest/testquestiontype.php
  73. 4  question/type/upgrade.txt
  74. 3  repository/draftfiles_ajax.php
  75. 1  theme/afterburner/config.php
  76. 3  theme/afterburner/style/afterburner_dock.css
  77. 3  theme/afterburner/style/afterburner_settings.css
  78. 6  theme/afterburner/style/afterburner_styles.css
  79. 2  theme/formal_white/config.php
  80. 2  theme/formal_white/lang/en/theme_formal_white.php
  81. 22  theme/formal_white/layout/embedded.php
  82. 220  theme/formal_white/layout/frontpage.php
  83. 231  theme/formal_white/layout/general.php
  84. 193  theme/formal_white/layout/report.php
  85. 27  theme/formal_white/lib.php
  86. 9  theme/formal_white/settings.php
  87. 35  theme/formal_white/style/formal_white.css
  88. 4  theme/formal_white/style/frame.css
  89. 4  theme/formal_white/style/quiz.css
  90. 2  theme/formal_white/version.php
  91. 36  theme/magazine/config.php
  92. 7  theme/magazine/style/colors.css
  93. 39  theme/magazine/style/core.css
  94. 21  theme/sky_high/config.php
  95. 77  theme/sky_high/layout/frontpage.php
  96. 98  theme/sky_high/layout/general.php
  97. 49  theme/sky_high/style/core.css
  98. 5  theme/sky_high/style/settings.css
  99. 99  theme/styles.php
  100. 54  theme/styles_debug.php
  101. 2  user/externallib.php
  102. 4  version.php
  103. 6  webservice/rest/locallib.php
4  admin/settings/subsystems.php
@@ -43,4 +43,6 @@
43 43
     $checkbox->set_affects_modinfo(true);
44 44
 
45 45
     $optionalsubsystems->add(new admin_setting_configcheckbox('enableplagiarism', new lang_string('enableplagiarism','plagiarism'), new lang_string('configenableplagiarism','plagiarism'), 0));
46  
-}
  46
+
  47
+    $optionalsubsystems->add(new admin_setting_configcheckbox('enablecssoptimiser', new lang_string('enablecssoptimiser','admin'), new lang_string('enablecssoptimiser_desc','admin'), 0));
  48
+}
2  backup/util/helper/restore_decode_processor.class.php
@@ -63,7 +63,7 @@ public function add_content($content) {
63 63
 
64 64
     public function add_rule($rule) {
65 65
         if (!$rule instanceof restore_decode_rule) {
66  
-            throw new restore_decode_processor_exception('incorrect_restore_decode_rule', get_class($content));
  66
+            throw new restore_decode_processor_exception('incorrect_restore_decode_rule', get_class($rule));
67 67
         }
68 68
         $rule->set_restoreid($this->restoreid);
69 69
         $rule->set_wwwroots($this->sourcewwwroot, $this->targetwwwroot);
2  backup/util/loggers/file_logger.class.php
@@ -61,7 +61,7 @@ public function __sleep() {
61 61
     public function __wakeup() {
62 62
         if ($this->level > backup::LOG_NONE) { // Only create the file if we are going to log something
63 63
             if (! $this->fhandle = fopen($this->fullpath, 'a')) {
64  
-                throw new base_logger_exception('error_opening_file', $fullpath);
  64
+                throw new base_logger_exception('error_opening_file', $this->fullpath);
65 65
             }
66 66
         }
67 67
     }
7  blocks/navigation/renderer.php
@@ -30,12 +30,14 @@ protected function navigation_node($items, $attrs=array(), $expansionlimit=null,
30 30
             $isexpandable = (empty($expansionlimit) || ($item->type > navigation_node::TYPE_ACTIVITY || $item->type < $expansionlimit) || ($item->contains_active_node() && $item->children->count() > 0));
31 31
             $isbranch = $isexpandable && ($item->children->count() > 0 || ($item->has_children() && (isloggedin() || $item->type <= navigation_node::TYPE_CATEGORY)));
32 32
 
33  
-            $hasicon = ((!$isbranch || $item->type == navigation_node::TYPE_ACTIVITY )&& $item->icon instanceof renderable);
  33
+            $hasicon = ((!$isbranch || $item->type == navigation_node::TYPE_ACTIVITY || $item->type == navigation_node::TYPE_RESOURCE) && $item->icon instanceof renderable);
34 34
 
35 35
             if ($hasicon) {
36 36
                 $icon = $this->output->render($item->icon);
37  
-                $content = $icon.$content; // use CSS for spacing of icons
  37
+            } else {
  38
+                $icon = '';
38 39
             }
  40
+            $content = $icon.$content; // use CSS for spacing of icons
39 41
             if ($item->helpbutton !== null) {
40 42
                 $content = trim($item->helpbutton).html_writer::tag('span', $content, array('class'=>'clearhelpbutton'));
41 43
             }
@@ -57,6 +59,7 @@ protected function navigation_node($items, $attrs=array(), $expansionlimit=null,
57 59
             } else if ($item->action instanceof action_link) {
58 60
                 //TODO: to be replaced with something else
59 61
                 $link = $item->action;
  62
+                $link->text = $icon.$link->text;
60 63
                 $link->attributes = array_merge($link->attributes, $attributes);
61 64
                 $content = $this->output->render($link);
62 65
                 $linkrendered = true;
2  calendar/lib.php
@@ -1796,7 +1796,7 @@ public function __isset($key) {
1796 1796
      * @return stdClass
1797 1797
      */
1798 1798
     protected function calculate_context(stdClass $data) {
1799  
-        global $USER;
  1799
+        global $USER, $DB;
1800 1800
 
1801 1801
         $context = null;
1802 1802
         if (isset($data->courseid) && $data->courseid > 0) {
26  config-dist.php
@@ -385,6 +385,32 @@
385 385
 //
386 386
 //     $CFG->extramemorylimit = 1G;
387 387
 //
  388
+// The CSS files the Moodle produces can be extremely large and complex, especially
  389
+// if you are using a custom theme that builds upon several other themes.
  390
+// In Moodle 2.3 a CSS optimiser was added as an experimental feature for advanced
  391
+// users. The CSS optimiser organises the CSS in order to reduce the overall number
  392
+// of rules and styles being sent to the client. It does this by collating the
  393
+// CSS before it is cached removing excess styles and rules and stripping out any
  394
+// extraneous content such as comments and empty rules.
  395
+// The following settings are used to enable and control the optimisation.
  396
+//
  397
+// Enable the CSS optimiser. This will only optimise the CSS if themedesignermode
  398
+// is not enabled. This can be set through the UI however it is noted here as well
  399
+// because the other CSS optimiser settings can not be set through the UI.
  400
+//
  401
+//      $CFG->enablecssoptimiser = true;
  402
+//
  403
+// If set the CSS optimiser will add stats about the optimisation to the top of
  404
+// the optimised CSS file. You can then inspect the CSS to see the affect the CSS
  405
+// optimiser is having.
  406
+//
  407
+//      $CFG->cssoptimiserstats = true;
  408
+//
  409
+// If set the CSS that is optimised will still retain a minimalistic formatting
  410
+// so that anyone wanting to can still clearly read it.
  411
+//
  412
+//      $CFG->cssoptimiserpretty = true;
  413
+//
388 414
 //=========================================================================
389 415
 // 8. SETTINGS FOR DEVELOPMENT SERVERS - not intended for production use!!!
390 416
 //=========================================================================
4  course/format/topics/format.php
@@ -189,9 +189,9 @@
189 189
         if ($PAGE->user_is_editing() && has_capability('moodle/course:update', get_context_instance(CONTEXT_COURSE, $course->id))) {
190 190
 
191 191
             if ($course->marker == $section) {  // Show the "light globe" on/off
192  
-                echo '<a href="view.php?id='.$course->id.'&amp;marker=0&amp;sesskey='.sesskey().'#section-'.$section.'" title="'.$strmarkedthistopic.'">'.'<img src="'.$OUTPUT->pix_url('i/marked') . '" alt="'.$strmarkedthistopic.'" /></a><br />';
  192
+                echo '<a href="view.php?id='.$course->id.'&amp;marker=0&amp;sesskey='.sesskey().'#section-'.$section.'" title="'.$strmarkedthistopic.'">'.'<img src="'.$OUTPUT->pix_url('i/marked') . '" alt="'.$strmarkedthistopic.'" class="icon"/></a><br />';
193 193
             } else {
194  
-                echo '<a href="view.php?id='.$course->id.'&amp;marker='.$section.'&amp;sesskey='.sesskey().'#section-'.$section.'" title="'.$strmarkthistopic.'">'.'<img src="'.$OUTPUT->pix_url('i/marker') . '" alt="'.$strmarkthistopic.'" /></a><br />';
  194
+                echo '<a href="view.php?id='.$course->id.'&amp;marker='.$section.'&amp;sesskey='.sesskey().'#section-'.$section.'" title="'.$strmarkthistopic.'">'.'<img src="'.$OUTPUT->pix_url('i/marker') . '" alt="'.$strmarkthistopic.'" class="icon"/></a><br />';
195 195
             }
196 196
 
197 197
             if ($thissection->visible) {        // Show the hide/show eye
2  course/lib.php
@@ -818,7 +818,7 @@ function print_log_ods($course, $user, $date, $order='l.time DESC', $modname,
818 818
 
819 819
         $coursecontext = get_context_instance(CONTEXT_COURSE, $course->id);
820 820
 
821  
-        $myxls->write_string($row, 0, format_string($courses[$log->course], true, array('context' => $context)));
  821
+        $myxls->write_string($row, 0, format_string($courses[$log->course], true, array('context' => $coursecontext)));
822 822
         $myxls->write_date($row, 1, $log->time);
823 823
         $myxls->write_string($row, 2, $log->ip);
824 824
         $fullname = fullname($log, has_capability('moodle/site:viewfullnames', $coursecontext));
44  enrol/externallib.php
@@ -172,26 +172,8 @@ public static function get_enrolled_users($courseid, $options) {
172 172
             }
173 173
         }
174 174
 
175  
-        // to overwrite this parameter, you need role:review capability
176  
-        if ($withcapability) {
177  
-            require_capability('moodle/role:review', $coursecontext);
178  
-        }
179  
-        // need accessallgroups capability if you want to overwrite this option
180  
-        if (!empty($groupid) && groups_is_member($groupid)) {
181  
-            require_capability('moodle/site:accessallgroups', $context);
182  
-        }
183  
-        // to overwrite this option, you need course:enrolereview permission
184  
-        if ($onlyactive) {
185  
-            require_capability('moodle/course:enrolreview', $coursecontext);
186  
-        }
187  
-
188  
-        list($coursectxselect, $coursectxjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx');
189  
-        $coursesql = "SELECT c.* $coursectxselect
190  
-                        FROM {course} c $coursectxjoin
191  
-                       WHERE c.id = $courseid";
192  
-        $course = $DB->get_record_sql($coursesql);
193  
-        context_instance_preload($course);
194  
-        $coursecontext = get_context_instance(CONTEXT_COURSE, $params['courseid']);
  175
+        $course = $DB->get_record('course', array('id'=>$courseid), '*', MUST_EXIST);
  176
+        $coursecontext = get_context_instance(CONTEXT_COURSE, $courseid);
195 177
         if ($courseid == SITEID) {
196 178
             $context = get_system_context();
197 179
         } else {
@@ -206,9 +188,26 @@ public static function get_enrolled_users($courseid, $options) {
206 188
             throw new moodle_exception(get_string('errorcoursecontextnotvalid' , 'webservice', $exceptionparam));
207 189
         }
208 190
 
  191
+        if ($courseid == SITEID) {
  192
+            require_capability('moodle/site:viewparticipants', $context);
  193
+        } else {
  194
+            require_capability('moodle/course:viewparticipants', $context);
  195
+        }
  196
+        // to overwrite this parameter, you need role:review capability
  197
+        if ($withcapability) {
  198
+            require_capability('moodle/role:review', $coursecontext);
  199
+        }
  200
+        // need accessallgroups capability if you want to overwrite this option
  201
+        if (!empty($groupid) && groups_is_member($groupid)) {
  202
+            require_capability('moodle/site:accessallgroups', $coursecontext);
  203
+        }
  204
+        // to overwrite this option, you need course:enrolereview permission
  205
+        if ($onlyactive) {
  206
+            require_capability('moodle/course:enrolreview', $coursecontext);
  207
+        }
  208
+
209 209
         list($enrolledsql, $enrolledparams) = get_enrolled_sql($coursecontext, $withcapability, $groupid, $onlyactive);
210 210
         list($ctxselect, $ctxjoin) = context_instance_preload_sql('u.id', CONTEXT_USER, 'ctx');
211  
-        $records = $DB->get_records_sql($enrolledsql, $enrolledparams);
212 211
         $sqlparams['courseid'] = $courseid;
213 212
         $sql = "SELECT u.* $ctxselect
214 213
                   FROM {user} u $ctxjoin
@@ -217,9 +216,6 @@ public static function get_enrolled_users($courseid, $options) {
217 216
         $enrolledusers = $DB->get_recordset_sql($sql, $enrolledparams);
218 217
         $users = array();
219 218
         foreach ($enrolledusers as $user) {
220  
-            if (!empty($user->deleted)) {
221  
-                continue;
222  
-            }
223 219
             context_instance_preload($user);
224 220
             if ($userdetails = user_get_user_details($user, $course, $userfields)) {
225 221
                 $users[] = $userdetails;
2  grade/grading/lib.php
@@ -461,7 +461,7 @@ public function extend_settings_navigation(settings_navigation $settingsnav, nav
461 461
      * @return grading_controller
462 462
      */
463 463
     public function get_controller($method) {
464  
-        global $CFG;
  464
+        global $CFG, $DB;
465 465
 
466 466
         $this->ensure_isset(array('context', 'component', 'area'));
467 467
 
4  install/lang/de/install.php
@@ -33,7 +33,7 @@
33 33
 $string['admindirname'] = 'Admin-Verzeichnis';
34 34
 $string['availablelangs'] = 'Verfügbare Sprachpakete';
35 35
 $string['chooselanguagehead'] = 'Sprache wählen';
36  
-$string['chooselanguagesub'] = 'Wählen Sie eine Sprache, die Sie während der Installation verwenden wollen. Die ausgewählte Sprache wird nach der Installation als Standardsprache der Instanz benutzt, aber können Sie die Sprache jederzeit ändern.';
  36
+$string['chooselanguagesub'] = 'Wählen Sie eine Sprache, die Sie während der Installation verwenden wollen. Die ausgewählte Sprache wird nach der Installation als Standardsprache der Instanz benutzt, aber Sie dürfen die Sprache jederzeit ändern.';
37 37
 $string['clialreadyconfigured'] = 'Die Datei config.php existiert bereits. Bitte benutzen Sie admin/cli/install_database.php, wenn sie diese Website installieren möchten.';
38 38
 $string['clialreadyinstalled'] = 'Die Datei config.php existiert bereits. Bitte benutzen Sie admin/cli/upgrade.php, wenn Sie diese Website aktualisieren möchten.';
39 39
 $string['cliinstallheader'] = 'Installation von Moodle {$a} über die Kommandozeile';
@@ -45,7 +45,7 @@
45 45
 $string['dbprefix'] = 'Tabellen-Prefix';
46 46
 $string['dirroot'] = 'Moodle-Verzeichnis';
47 47
 $string['environmenthead'] = 'Installationsvoraussetzungen werden geprüft ...';
48  
-$string['environmentsub2'] = 'Jede Moodle-Version hat Mindestvoraussetzungen für der PHP-Version und für einige verbindliche PHP-Extensions. Vor einer Installation oder einer Aktualisierung wird immer eine vollständige Prüfung der Serverausstattung durchgeführt. Bitte fragen Sie den Administrator Ihres Servers, wenn Sie mit der Installation einer neuen Version oder mit der Aktivierung von PHP-Extensions nicht weiterkommen.';
  48
+$string['environmentsub2'] = 'Jede Moodle-Version hat Mindestvoraussetzungen für der PHP-Version und für verbindliche PHP-Extensions. Vor einer Installation oder einer Aktualisierung wird eine vollständige Prüfung durchgeführt. Bitte fragen Sie den Server-Administrator, wenn Sie mit der Installation einer neuen Version oder mit der Aktivierung von PHP-Extensions nicht weiterkommen.';
49 49
 $string['errorsinenvironment'] = 'Fehler bei der Prüfung der Systemvoraussetzungen!';
50 50
 $string['installation'] = 'Installation';
51 51
 $string['langdownloaderror'] = 'Leider konnte das Sprachpaket \'{$a}\' nicht heruntergeladen werden. Die Installation wird in englischer Sprache fortgesetzt.';
3  install/lang/de_du/install.php
@@ -30,7 +30,8 @@
30 30
 
31 31
 defined('MOODLE_INTERNAL') || die();
32 32
 
33  
-$string['chooselanguagesub'] = 'Wähle eine Sprache, die du während der Installation verwenden möchtest. Nach der Installation kannst du die Sprache für die Oberfläche und die Nutzer/innen festlegen.';
  33
+$string['chooselanguagesub'] = 'Wähle eine Sprache, die du während der Installation verwenden möchtest. Die ausgewählte Sprache wird nach der Installation als Standardsprache der Instanz benutzt, aber du darfst die Sprache jederzeit ändern.';
  34
+$string['environmentsub2'] = 'Jede Moodle-Version hat Mindestvoraussetzungen für der PHP-Version und für verbindliche PHP-Extensions. Vor einer Installation oder einer Aktualisierung wird eine vollständige Prüfung durchgeführt. Bitte frage den Server-Administrator, wenn du mit der Installation einer neuen Version oder mit der Aktivierung von PHP-Extensions nicht weiterkommst.';
34 35
 $string['memorylimithelp'] = '<p>Die PHP-Einstellung memory_limit für deinen Server ist zur Zeit auf {$a} eingestellt. </p>
35 36
 <p>Dies wird vermutlich zu Problemen führen, wenn du Moodle mit vielen Aktivitäten oder vielen Nutzer/innen verwendst. </p>
36 37
 <p>Wir empfehlen die Einstellung zu erhöhen. Empfohlen werden 40M oder mehr. Dies kannst du auf verschiedene Arten machen:</p>
2  install/lang/de_kids/langconfig.php
@@ -31,5 +31,5 @@
31 31
 defined('MOODLE_INTERNAL') || die();
32 32
 
33 33
 $string['parentlanguage'] = 'de_du';
34  
-$string['thisdirection'] = '';
  34
+$string['thisdirection'] = 'ltr';
35 35
 $string['thislanguage'] = 'Deutsch - Kids';
3  install/lang/he/install.php
@@ -92,8 +92,7 @@
92 92
 (במקרים של גרסת 5.0.x תוכל גם לרדת בגירסה ל- 4.4.x)
93 93
 </p>';
94 94
 $string['welcomep10'] = '{$a->installername} ({$a->installerversion})';
95  
-$string['welcomep20'] = 'הינך רואה את עמוד זה מפני שהתקנת והפעלת בהלכה את <strong> $a-packname {$a->packversion} 
96  
-</strong>
  95
+$string['welcomep20'] = 'הינך רואה את עמוד זה מפני שהתקנת והפעלת בהלכה את <strong>{$a->packname} {$a->packversion}</strong>
97 96
 חבילה במחשבך. ברכותינו!';
98 97
 $string['welcomep30'] = 'גירסת <strong>{$a->installername}</strong> כוללת את היישומים ליצור סביבה אשר בה <strong> Moodle </strong>
99 98
 יפעל דהיינו:';
2  lang/en/admin.php
@@ -466,6 +466,8 @@
466 466
 $string['enablecourseajax'] = 'Enable AJAX course editing';
467 467
 $string['enablecourseajax_desc'] = 'Allow AJAX when editing main course pages. Note that the course format and the theme must support AJAX editing and the user has to enable AJAX in their profiles, too.';
468 468
 $string['enablecourserequests'] = 'Enable course requests';
  469
+$string['enablecssoptimiser'] = 'Enable CSS optimiser';
  470
+$string['enablecssoptimiser_desc'] = 'When enabled CSS will be run through an optimisation process before being cached. The optimiser processes the CSS removing duplicate rules and styles, as well as white space removeable and reformatting. Please note turning this on at the same time as theme designer mode is aweful for performance but will help theme designers create optimised CSS.';
469 471
 $string['enabledevicedetection'] = 'Enable device detection';
470 472
 $string['enablegravatar'] = 'Enable Gravatar';
471 473
 $string['enablegravatar_help'] = 'When enabled Moodle will attempt to fetch a user profile picture from Gravatar if the user has not uploaded an image.';
1  lang/en/error.php
@@ -435,6 +435,7 @@
435 435
 $string['secretalreadyused'] = 'Change password confirmation link was already used, password was not changed';
436 436
 $string['sectionnotexist'] = 'This section does not exist';
437 437
 $string['sendmessage'] = 'Send message';
  438
+$string['serverconnection'] = 'Error connecting to the server';
438 439
 $string['servicedonotexist'] = 'The service does not exist';
439 440
 $string['sessionwaiterr'] = 'Timed out while waiting for session lock.<br />Wait for your current requests to finish and try again later.';
440 441
 $string['sessioncookiesdisable'] = 'Incorrect use of require_key_login() - session cookies must be disabled!';
4  lang/en/moodle.php
@@ -451,9 +451,9 @@
451 451
 $string['displayingrecords'] = 'Displaying {$a} records';
452 452
 $string['displayingusers'] = 'Displaying users {$a->start} to {$a->end}';
453 453
 $string['displayonpage'] = 'Display on page';
454  
-$string['dndenabled'] = 'You can drag and drop files into this box to upload them';
  454
+$string['dndenabled'] = 'Drag and drop available';
455 455
 $string['dndenabled_help'] = 'You can drag one or more files from your desktop and drop them onto the box below to upload them.<br />Note: this may not work with other web browsers';
456  
-$string['dndenabled_single'] = 'you can drag and drop a file into this box to upload it';
  456
+$string['dndenabled_insentence'] = 'drag and drop available';
457 457
 $string['documentation'] = 'Moodle documentation';
458 458
 $string['down'] = 'Down';
459 459
 $string['download'] = 'Download';
1  lang/en/question.php
@@ -99,6 +99,7 @@
99 99
 $string['deletequestionscheck'] = 'Are you absolutely sure you want to delete the following questions?<br /><br />{$a}';
100 100
 $string['deletingbehaviour'] = 'Deleting question behaviour \'{$a}\'';
101 101
 $string['deletingqtype'] = 'Deleting question type \'{$a}\'';
  102
+$string['didnotmatchanyanswer'] = '[Did not match any answer]';
102 103
 $string['disabled'] = 'Disabled';
103 104
 $string['disterror'] = 'The distribution {$a} caused problems';
104 105
 $string['donothing'] = 'Don\'t copy or move files or change links.';
3,584  lib/csslib.php
3584 additions, 0 deletions not shown
5  lib/enrollib.php
@@ -1039,10 +1039,7 @@ public function get_description_text($instance) {
1039 1039
     protected function load_config() {
1040 1040
         if (!isset($this->config)) {
1041 1041
             $name = $this->get_name();
1042  
-            if (!$config = get_config("enrol_$name")) {
1043  
-                $config = new stdClass();
1044  
-            }
1045  
-            $this->config = $config;
  1042
+            $this->config = get_config("enrol_$name");
1046 1043
         }
1047 1044
     }
1048 1045
 
47  lib/form/dndupload.js
@@ -163,13 +163,13 @@ M.form_dndupload = {
163 163
             return false;
164 164
         }
165 165
 
  166
+        e.preventDefault();
  167
+        e.stopPropagation();
  168
+
166 169
         if (this.reached_maxfiles()) {
167 170
             return false;
168 171
         }
169 172
 
170  
-        e.preventDefault();
171  
-        e.stopPropagation();
172  
-
173 173
         return true;
174 174
     },
175 175
 
@@ -324,7 +324,6 @@ M.form_dndupload = {
324 324
     update_filemanager: function() {
325 325
         if (this.filemanager) {
326 326
             // update the filemanager that we've uploaded the files
327  
-            this.hide_progress_spinner();
328 327
             this.filemanager.filepicker_callback();
329 328
         }
330 329
     },
@@ -335,6 +334,7 @@ M.form_dndupload = {
335 334
     upload_file: function(file) {
336 335
         if (file.size > this.maxbytes && this.maxbytes > 0) {
337 336
             // Check filesize before attempting to upload
  337
+            this.hide_progress_spinner();
338 338
             alert(M.util.get_string('uploadformlimit', 'moodle')+"\n'"+file.name+"'");
339 339
             return false;
340 340
         }
@@ -348,26 +348,29 @@ M.form_dndupload = {
348 348
         var xhr = new XMLHttpRequest();
349 349
         var self = this;
350 350
         xhr.onreadystatechange = function() { // Process the server response
351  
-            if (xhr.readyState == 4 && xhr.status == 200) {
352  
-                var result = JSON.parse(xhr.responseText);
353  
-                if (result) {
354  
-                    if (result.error) {
355  
-                        self.hide_progress_spinner();
356  
-                        alert(result.error);
357  
-                    } else if (self.callback) {
358  
-                        // Only update the filepicker if there were no errors
359  
-                        self.hide_progress_spinner();
360  
-                        if (result.event == 'fileexists') {
361  
-                            // Do not worry about this, as we only care about the last
362  
-                            // file uploaded, with the filepicker
363  
-                            result.file = result.newfile.filename;
364  
-                            result.url = result.newfile.url;
  351
+            if (xhr.readyState == 4) {
  352
+                self.hide_progress_spinner();
  353
+                if (xhr.status == 200) {
  354
+                    var result = JSON.parse(xhr.responseText);
  355
+                    if (result) {
  356
+                        if (result.error) {
  357
+                            alert(result.error);
  358
+                        } else if (self.callback) {
  359
+                            // Only update the filepicker if there were no errors
  360
+                            if (result.event == 'fileexists') {
  361
+                                // Do not worry about this, as we only care about the last
  362
+                                // file uploaded, with the filepicker
  363
+                                result.file = result.newfile.filename;
  364
+                                result.url = result.newfile.url;
  365
+                            }
  366
+                            result.client_id = self.clientid;
  367
+                            self.callback(result);
  368
+                        } else {
  369
+                            self.update_filemanager();
365 370
                         }
366  
-                        result.client_id = self.clientid;
367  
-                        self.callback(result);
368  
-                    } else {
369  
-                        self.update_filemanager();
370 371
                     }
  372
+                } else {
  373
+                    alert(M.util.get_string('serverconnection', 'error'));
371 374
                 }
372 375
             }
373 376
         };
13  lib/form/filemanager.js
@@ -76,7 +76,7 @@ M.form_filemanager.init = function(Y, options) {
76 76
                 this.filecount = 0;
77 77
             }
78 78
             this.setup_buttons();
79  
-            this.render();
  79
+            this.refresh(this.currentpath); // MDL-31113 get latest list from server
80 80
         },
81 81
 
82 82
         wait: function(client_id) {
@@ -141,15 +141,18 @@ M.form_filemanager.init = function(Y, options) {
141 141
             }
142 142
         },
143 143
         filepicker_callback: function(obj) {
144  
-            var button_addfile  = Y.one("#btnadd-"+this.client_id);
145 144
             this.filecount++;
  145
+            this.check_buttons();
  146
+            this.refresh(this.currentpath);
  147
+        },
  148
+        check_buttons: function() {
  149
+            var button_addfile  = Y.one("#btnadd-"+this.client_id);
146 150
             if (this.filecount > 0) {
147 151
                 Y.one("#btndwn-"+this.client_id).setStyle('display', 'inline');
148 152
             }
149 153
             if (this.filecount >= this.maxfiles && this.maxfiles!=-1) {
150 154
                 button_addfile.setStyle('display', 'none');
151 155
             }
152  
-            this.refresh(this.currentpath);
153 156
         },
154 157
         refresh: function(filepath) {
155 158
             var scope = this;
@@ -164,6 +167,8 @@ M.form_filemanager.init = function(Y, options) {
164 167
                 scope: scope,
165 168
                 params: {'filepath':filepath},
166 169
                 callback: function(id, obj, args) {
  170
+                    scope.filecount = obj.filecount;
  171
+                    scope.check_buttons();
167 172
                     scope.options = obj;
168 173
                     scope.render(obj);
169 174
                 }
@@ -298,6 +303,8 @@ M.form_filemanager.init = function(Y, options) {
298 303
                             scope: scope,
299 304
                             params: params,
300 305
                             callback: function(id, obj, args) {
  306
+                                scope.filecount = obj.filecount;
  307
+                                scope.check_buttons();
301 308
                                 scope.options = obj;
302 309
                                 scope.render(obj);
303 310
                             }
4  lib/form/filemanager.php
@@ -274,7 +274,7 @@ function form_filemanager_render($options) {
274 274
     }
275 275
 
276 276
     $maxsize = get_string('maxfilesize', 'moodle', display_size(get_max_upload_file_size($CFG->maxbytes, $course_maxbytes, $options->maxbytes)));
277  
-    $strdndenabled = get_string('dndenabled', 'moodle').$OUTPUT->help_icon('dndenabled');
  277
+    $strdndenabled = get_string('dndenabled_insentence', 'moodle').$OUTPUT->help_icon('dndenabled');
278 278
     $html .= <<<FMHTML
279 279
 <div class="filemanager-loading mdl-align" id='filemanager-loading-{$client_id}'>
280 280
 $icon_progress
@@ -315,7 +315,7 @@ function form_filemanager_render($options) {
315 315
              array('cannotdeletefile', 'error'), array('confirmdeletefile', 'repository'),
316 316
              array('nopathselected', 'repository'), array('popupblockeddownload', 'repository'),
317 317
              array('draftareanofiles', 'repository'), array('path', 'moodle'), array('setmainfile', 'repository'),
318  
-             array('moving', 'repository'), array('files', 'moodle')
  318
+             array('moving', 'repository'), array('files', 'moodle'), array('serverconnection', 'error')
319 319
         )
320 320
     );
321 321
     $PAGE->requires->js_module($module);
136  lib/moodlelib.php
@@ -1318,7 +1318,7 @@ function get_config($plugin, $name = NULL) {
1318 1318
         if ($localcfg) {
1319 1319
             return (object)$localcfg;
1320 1320
         } else {
1321  
-            return null;
  1321
+            return new stdClass();
1322 1322
         }
1323 1323
 
1324 1324
     } else {
@@ -1815,17 +1815,19 @@ function get_user_preferences($name = null, $default = null, $user = null) {
1815 1815
 /**
1816 1816
  * Given date parts in user time produce a GMT timestamp.
1817 1817
  *
1818  
- * @todo Finish documenting this function
  1818
+ * @package core
  1819
+ * @category time
1819 1820
  * @param int $year The year part to create timestamp of
1820 1821
  * @param int $month The month part to create timestamp of
1821 1822
  * @param int $day The day part to create timestamp of
1822 1823
  * @param int $hour The hour part to create timestamp of
1823 1824
  * @param int $minute The minute part to create timestamp of
1824 1825
  * @param int $second The second part to create timestamp of
1825  
- * @param mixed $timezone Timezone modifier, if 99 then use default user's timezone
  1826
+ * @param int|float|string $timezone Timezone modifier, used to calculate GMT time offset.
  1827
+ *             if 99 then default user's timezone is used {@link http://docs.moodle.org/dev/Time_API#Timezone}
1826 1828
  * @param bool $applydst Toggle Daylight Saving Time, default true, will be
1827 1829
  *             applied only if timezone is 99 or string.
1828  
- * @return int timestamp
  1830
+ * @return int GMT timestamp
1829 1831
  */
1830 1832
 function make_timestamp($year, $month=1, $day=1, $hour=0, $minute=0, $second=0, $timezone=99, $applydst=true) {
1831 1833
 
@@ -1856,6 +1858,8 @@ function make_timestamp($year, $month=1, $day=1, $hour=0, $minute=0, $second=0,
1856 1858
  * Given an amount of time in seconds, returns string
1857 1859
  * formatted nicely as weeks, days, hours etc as needed
1858 1860
  *
  1861
+ * @package core
  1862
+ * @category time
1859 1863
  * @uses MINSECS
1860 1864
  * @uses HOURSECS
1861 1865
  * @uses DAYSECS
@@ -1931,13 +1935,16 @@ function format_time($totalsecs, $str=NULL) {
1931 1935
  * If parameter fixday = true (default), then take off leading
1932 1936
  * zero from %d, else maintain it.
1933 1937
  *
  1938
+ * @package core
  1939
+ * @category time
1934 1940
  * @param int $date the timestamp in UTC, as obtained from the database.
1935 1941
  * @param string $format strftime format. You should probably get this using
1936  
- *      get_string('strftime...', 'langconfig');
1937  
- * @param mixed $timezone by default, uses the user's time zone. if numeric and
1938  
- *      not 99 then daylight saving will not be added.
  1942
+ *        get_string('strftime...', 'langconfig');
  1943
+ * @param int|float|string  $timezone by default, uses the user's time zone. if numeric and
  1944
+ *        not 99 then daylight saving will not be added.
  1945
+ *        {@link http://docs.moodle.org/dev/Time_API#Timezone}
1939 1946
  * @param bool $fixday If true (default) then the leading zero from %d is removed.
1940  
- *      If false then the leading zero is maintained.
  1947
+ *        If false then the leading zero is maintained.
1941 1948
  * @return string the formatted date/time.
1942 1949
  */
1943 1950
 function userdate($date, $format = '', $timezone = 99, $fixday = true) {
@@ -2001,11 +2008,12 @@ function userdate($date, $format = '', $timezone = 99, $fixday = true) {
2001 2008
  * Given a $time timestamp in GMT (seconds since epoch),
2002 2009
  * returns an array that represents the date in user time
2003 2010
  *
2004  
- * @todo Finish documenting this function
  2011
+ * @package core
  2012
+ * @category time
2005 2013
  * @uses HOURSECS
2006 2014
  * @param int $time Timestamp in GMT
2007  
- * @param mixed $timezone offset time with timezone, if float and not 99, then no
2008  
- *        dst offset is applyed
  2015
+ * @param float|int|string $timezone offset's time with timezone, if float and not 99, then no
  2016
+ *        dst offset is applyed {@link http://docs.moodle.org/dev/Time_API#Timezone}
2009 2017
  * @return array An array that represents the date in user time
2010 2018
  */
2011 2019
 function usergetdate($time, $timezone=99) {
@@ -2050,9 +2058,13 @@ function usergetdate($time, $timezone=99) {
2050 2058
  * Given a GMT timestamp (seconds since epoch), offsets it by
2051 2059
  * the timezone.  eg 3pm in India is 3pm GMT - 7 * 3600 seconds
2052 2060
  *
  2061
+ * @package core
  2062
+ * @category time
2053 2063
  * @uses HOURSECS
2054  
- * @param  int $date Timestamp in GMT
2055  
- * @param float $timezone
  2064
+ * @param int $date Timestamp in GMT
  2065
+ * @param float|int|string $timezone timezone to calculate GMT time offset before
  2066
+ *        calculating user time, 99 is default user timezone
  2067
+ *        {@link http://docs.moodle.org/dev/Time_API#Timezone}
2056 2068
  * @return int
2057 2069
  */
2058 2070
 function usertime($date, $timezone=99) {
@@ -2069,8 +2081,12 @@ function usertime($date, $timezone=99) {
2069 2081
  * Given a time, return the GMT timestamp of the most recent midnight
2070 2082
  * for the current user.
2071 2083
  *
  2084
+ * @package core
  2085
+ * @category time
2072 2086
  * @param int $date Timestamp in GMT
2073  
- * @param float $timezone Defaults to user's timezone
  2087
+ * @param float|int|string $timezone timezone to calculate GMT time offset before
  2088
+ *        calculating user midnight time, 99 is default user timezone
  2089
+ *        {@link http://docs.moodle.org/dev/Time_API#Timezone}
2074 2090
  * @return int Returns a GMT timestamp
2075 2091
  */
2076 2092
 function usergetmidnight($date, $timezone=99) {
@@ -2085,7 +2101,11 @@ function usergetmidnight($date, $timezone=99) {
2085 2101
 /**
2086 2102
  * Returns a string that prints the user's timezone
2087 2103
  *
2088  
- * @param float $timezone The user's timezone
  2104
+ * @package core
  2105
+ * @category time
  2106
+ * @param float|int|string $timezone timezone to calculate GMT time offset before
  2107
+ *        calculating user timezone, 99 is default user timezone
  2108
+ *        {@link http://docs.moodle.org/dev/Time_API#Timezone}
2089 2109
  * @return string
2090 2110
  */
2091 2111
 function usertimezone($timezone=99) {
@@ -2121,9 +2141,11 @@ function usertimezone($timezone=99) {
2121 2141
  * Returns a float which represents the user's timezone difference from GMT in hours
2122 2142
  * Checks various settings and picks the most dominant of those which have a value
2123 2143
  *
2124  
- * @global object
2125  
- * @global object
2126  
- * @param float $tz If this value is provided and not equal to 99, it will be returned as is and no other settings will be checked
  2144
+ * @package core
  2145
+ * @category time
  2146
+ * @param float|int|string $tz timezone to calculate GMT time offset for user,
  2147
+ *        99 is default user timezone
  2148
+ *        {@link http://docs.moodle.org/dev/Time_API#Timezone}
2127 2149
  * @return float
2128 2150
  */
2129 2151
 function get_user_timezone_offset($tz = 99) {
@@ -2146,9 +2168,11 @@ function get_user_timezone_offset($tz = 99) {
2146 2168
 /**
2147 2169
  * Returns an int which represents the systems's timezone difference from GMT in seconds
2148 2170
  *
2149  
- * @global object
2150  
- * @param mixed $tz timezone
2151  
- * @return int if found, false is timezone 99 or error
  2171
+ * @package core
  2172
+ * @category time
  2173
+ * @param float|int|string $tz timezone for which offset is required.
  2174
+ *        {@link http://docs.moodle.org/dev/Time_API#Timezone}
  2175
+ * @return int|bool if found, false is timezone 99 or error
2152 2176
  */
2153 2177
 function get_timezone_offset($tz) {
2154 2178
     global $CFG;
@@ -2173,10 +2197,12 @@ function get_timezone_offset($tz) {
2173 2197
  * means that for this timezone there are also DST rules to be taken into account
2174 2198
  * Checks various settings and picks the most dominant of those which have a value
2175 2199
  *
2176  
- * @global object
2177  
- * @global object
2178  
- * @param mixed $tz If this value is provided and not equal to 99, it will be returned as is and no other settings will be checked
2179  
- * @return mixed
  2200
+ * @package core
  2201
+ * @category time
  2202
+ * @param float|int|string $tz timezone to calculate GMT time offset before
  2203
+ *        calculating user timezone, 99 is default user timezone
  2204
+ *        {@link http://docs.moodle.org/dev/Time_API#Timezone}
  2205
+ * @return float|string
2180 2206
  */
2181 2207
 function get_user_timezone($tz = 99) {
2182 2208
     global $USER, $CFG;
@@ -2200,10 +2226,9 @@ function get_user_timezone($tz = 99) {
2200 2226
 /**
2201 2227
  * Returns cached timezone record for given $timezonename
2202 2228
  *
2203  
- * @global object
2204  
- * @global object
2205  
- * @param string $timezonename
2206  
- * @return mixed timezonerecord object or false
  2229
+ * @package core
  2230
+ * @param string $timezonename name of the timezone
  2231
+ * @return stdClass|bool timezonerecord or false
2207 2232
  */
2208 2233
 function get_timezone_record($timezonename) {
2209 2234
     global $CFG, $DB;
@@ -2218,18 +2243,16 @@ function get_timezone_record($timezonename) {
2218 2243
     }
2219 2244
 
2220 2245
     return $cache[$timezonename] = $DB->get_record_sql('SELECT * FROM {timezone}
2221  
-                                                        WHERE name = ? ORDER BY year DESC', array($timezonename), true);
  2246
+                                                        WHERE name = ? ORDER BY year DESC', array($timezonename), IGNORE_MULTIPLE);
2222 2247
 }
2223 2248
 
2224 2249
 /**
2225 2250
  * Build and store the users Daylight Saving Time (DST) table
2226 2251
  *
2227  
- * @global object
2228  
- * @global object
2229  
- * @global object
2230  
- * @param mixed $from_year Start year for the table, defaults to 1971
2231  
- * @param mixed $to_year End year for the table, defaults to 2035
2232  
- * @param mixed $strtimezone, if null or 99 then user's default timezone is used
  2252
+ * @package core
  2253
+ * @param int $from_year Start year for the table, defaults to 1971
  2254
+ * @param int $to_year End year for the table, defaults to 2035
  2255
+ * @param int|float|string $strtimezone, timezone to check if dst should be applyed.
2233 2256
  * @return bool
2234 2257
  */
2235 2258
 function calculate_user_dst_table($from_year = NULL, $to_year = NULL, $strtimezone = NULL) {
@@ -2357,11 +2380,13 @@ function calculate_user_dst_table($from_year = NULL, $to_year = NULL, $strtimezo
2357 2380
 /**
2358 2381
  * Calculates the required DST change and returns a Timestamp Array
2359 2382
  *
  2383
+ * @package core
  2384
+ * @category time
2360 2385
  * @uses HOURSECS
2361 2386
  * @uses MINSECS
2362  
- * @param mixed $year Int or String Year to focus on
  2387
+ * @param int|string $year Int or String Year to focus on
2363 2388
  * @param object $timezone Instatiated Timezone object
2364  
- * @return mixed Null, or Array dst=>xx, 0=>xx, std=>yy, 1=>yy
  2389
+ * @return array|null Array dst=>xx, 0=>xx, std=>yy, 1=>yy or NULL
2365 2390
  */
2366 2391
 function dst_changes_for_year($year, $timezone) {
2367 2392
 
@@ -2392,10 +2417,11 @@ function dst_changes_for_year($year, $timezone) {
2392 2417
  * Calculates the Daylight Saving Offset for a given date/time (timestamp)
2393 2418
  * - Note: Daylight saving only works for string timezones and not for float.
2394 2419
  *
2395  
- * @global object
  2420
+ * @package core
  2421
+ * @category time
2396 2422
  * @param int $time must NOT be compensated at all, it has to be a pure timestamp
2397  
- * @param mixed $strtimezone timezone for which offset is expected, if 99 or null
2398  
- *        then user's default timezone is used.
  2423
+ * @param int|float|string $strtimezone timezone for which offset is expected, if 99 or null
  2424
+ *        then user's default timezone is used. {@link http://docs.moodle.org/dev/Time_API#Timezone}
2399 2425
  * @return int
2400 2426
  */
2401 2427
 function dst_offset_on($time, $strtimezone = NULL) {
@@ -2440,13 +2466,14 @@ function dst_offset_on($time, $strtimezone = NULL) {
2440 2466
 }
2441 2467
 
2442 2468
 /**
2443  
- * ?
  2469
+ * Calculates when the day appears in specific month
2444 2470
  *
2445  
- * @todo Document what this function does
2446  
- * @param int $startday
2447  
- * @param int $weekday
2448  
- * @param int $month
2449  
- * @param int $year
  2471
+ * @package core
  2472
+ * @category time
  2473
+ * @param int $startday starting day of the month
  2474
+ * @param int $weekday The day when week starts (normally taken from user preferences)
  2475
+ * @param int $month The month whose day is sought
  2476
+ * @param int $year The year of the month whose day is sought
2450 2477
  * @return int
2451 2478
  */
2452 2479
 function find_day_in_month($startday, $weekday, $month, $year) {
@@ -2508,6 +2535,8 @@ function find_day_in_month($startday, $weekday, $month, $year) {
2508 2535
 /**
2509 2536
  * Calculate the number of days in a given month
2510 2537
  *
  2538
+ * @package core
  2539
+ * @category time
2511 2540
  * @param int $month The month whose day count is sought
2512 2541
  * @param int $year The year of the month whose day count is sought
2513 2542
  * @return int
@@ -2519,6 +2548,8 @@ function days_in_month($month, $year) {
2519 2548
 /**
2520 2549
  * Calculate the position in the week of a specific calendar day
2521 2550
  *
  2551
+ * @package core
  2552
+ * @category time
2522 2553
  * @param int $day The day of the date whose position in the week is sought
2523 2554
  * @param int $month The month of the date whose position in the week is sought
2524 2555
  * @param int $year The year of the date whose position in the week is sought
@@ -5028,6 +5059,17 @@ function email_to_user($user, $from, $subject, $messagetext, $messagehtml='', $a
5028 5059
         return true;
5029 5060
     }
5030 5061
 
  5062
+    if (!validate_email($user->email)) {
  5063
+        // we can not send emails to invalid addresses - it might create security issue or confuse the mailer
  5064
+        $invalidemail = "User $user->id (".fullname($user).") email ($user->email) is invalid! Not sending.";
  5065
+        error_log($invalidemail);
  5066
+        if (CLI_SCRIPT) {
  5067
+            // do not print this in standard web pages
  5068
+            mtrace($invalidemail);
  5069
+        }
  5070
+        return false;
  5071
+    }
  5072
+
5031 5073
     if (over_bounce_threshold($user)) {
5032 5074
         $bouncemsg = "User $user->id (".fullname($user).") is over bounce threshold! Not sending.";
5033 5075
         error_log($bouncemsg);
31  lib/navigationlib.php
@@ -127,6 +127,8 @@ class navigation_node implements renderable {
127 127
     protected static $fullmeurl = null;
128 128
     /** @var bool toogles auto matching of active node */
129 129
     public static $autofindactive = true;
  130
+    /** @var mixed If set to an int, that section will be included even if it has no activities */
  131
+    public $includesectionnum = false;
130 132
 
131 133
     /**
132 134
      * Constructs a new navigation_node
@@ -1172,13 +1174,29 @@ public function initialise() {
1172 1174
                     }
1173 1175
 
1174 1176
                     $this->add_course_essentials($coursenode, $course);
  1177
+
  1178
+                    // Get section number from $cm (if provided) - we need this
  1179
+                    // before loading sections in order to tell it to load this section
  1180
+                    // even if it would not normally display (=> it contains only
  1181
+                    // a label, which we are now editing)
  1182
+                    $sectionnum = isset($cm->sectionnum) ? $cm->sectionnum : 0;
  1183
+                    if ($sectionnum) {
  1184
+                        // This value has to be stored in a member variable because
  1185
+                        // otherwise we would have to pass it through a public API
  1186
+                        // to course formats and they would need to change their
  1187
+                        // functions to pass it along again...
  1188
+                        $this->includesectionnum = $sectionnum;
  1189
+                    } else {
  1190
+                        $this->includesectionnum = false;
  1191
+                    }
  1192
+
1175 1193
                     // Load the course sections into the page
1176 1194
                     $sections = $this->load_course_sections($course, $coursenode);
1177 1195
                     if ($course->id != SITEID) {
1178 1196
                         // Find the section for the $CM associated with the page and collect
1179 1197
                         // its section number.
1180  
-                        if (isset($cm->sectionnum)) {
1181  
-                            $cm->sectionnumber = $cm->sectionnum;
  1198
+                        if ($sectionnum) {
  1199
+                            $cm->sectionnumber = $sectionnum;
1182 1200
                         } else {
1183 1201
                             foreach ($sections as $section) {
1184 1202
                                 if ($section->id == $cm->section) {
@@ -1630,7 +1648,9 @@ protected function generate_sections_and_activities(stdClass $course) {
1630 1648
                         }
1631 1649
                     }
1632 1650
                     $activities[$cmid] = $activity;
1633  
-                    $sections[$key]->hasactivites = true;
  1651
+                    if ($activity->display) {
  1652
+                        $sections[$key]->hasactivites = true;
  1653
+                    }
1634 1654
                 }
1635 1655
             }
1636 1656
             $this->cache->set('course_sections_'.$course->id, $sections);
@@ -1678,7 +1698,8 @@ public function load_generic_course_sections(stdClass $course, navigation_node $
1678 1698
             if ($course->id == SITEID) {
1679 1699
                 $this->load_section_activities($coursenode, $section->section, $activities);
1680 1700
             } else {
1681  
-                if ((!$viewhiddensections && !$section->visible) || (!$this->showemptysections && !$section->hasactivites)) {
  1701
+                if ((!$viewhiddensections && !$section->visible) || (!$this->showemptysections &&
  1702
+                        !$section->hasactivites && $this->includesectionnum !== $section->section)) {
1682 1703
                     continue;
1683 1704
                 }
1684 1705
                 if ($namingfunctionexists) {
@@ -4047,6 +4068,8 @@ protected function convert_child($child, $depth=1) {
4047 4068
             $attributes['link'] = $child->action;
4048 4069
         } else if ($child->action instanceof moodle_url) {
4049 4070
             $attributes['link'] = $child->action->out();
  4071
+        } else if ($child->action instanceof action_link) {
  4072
+            $attributes['link'] = $child->action->url->out();
4050 4073
         }
4051 4074
         $attributes['hidden'] = ($child->hidden);
4052 4075
         $attributes['haschildren'] = ($child->children->count()>0 || $child->type == navigation_node::TYPE_CATEGORY);
2  lib/outputcomponents.php
@@ -1199,7 +1199,7 @@ public static function select_time($type, $name, $currenttime=0, $step=5, array
1199 1199
                     $timeunits[$i] = userdate(gmmktime(12,0,0,$i,15,2000), "%B");
1200 1200
                 }
1201 1201
                 $userdatetype = 'month';
1202  
-                $currentdate['month'] = $currentdate['mon'];
  1202
+                $currentdate['month'] = (int)$currentdate['mon'];
1203 1203
                 break;
1204 1204
             case 'days':
1205 1205
                 for ($i=1; $i<=31; $i++) {
2  lib/outputrenderers.php
@@ -1902,7 +1902,7 @@ public function render_file_picker(file_picker $fp) {
1902 1902
         $strsaved = get_string('filesaved', 'repository');
1903 1903
         $straddfile = get_string('openpicker', 'repository');
1904 1904
         $strloading  = get_string('loading', 'repository');
1905  
-        $strdndenabled = get_string('dndenabled_single', 'moodle');
  1905
+        $strdndenabled = get_string('dndenabled_insentence', 'moodle');
1906 1906
         $icon_progress = $OUTPUT->pix_icon('i/loading_small', $strloading).'';
1907 1907
 
1908 1908
         $currentfile = $options->currentfile;
2  lib/portfoliolib.php
@@ -353,7 +353,7 @@ public function to_html($format=null, $addstr=null) {
353 353
                 $formoutput .= "\n" . '</form>';
354 354
             break;
355 355
             case PORTFOLIO_ADD_ICON_LINK:
356  
-                $linkoutput .= '"><img class="portfolio-add-icon" src="' . $OUTPUT->pix_url('t/portfolioadd') . '" alt="' . $addstr .'" /></a>';
  356
+                $linkoutput .= '"><img class="portfolio-add-icon iconsmall" src="' . $OUTPUT->pix_url('t/portfolioadd') . '" alt="' . $addstr .'" /></a>';
357 357
             break;
358 358
             case PORTFOLIO_ADD_TEXT_LINK:
359 359
                 $linkoutput .= '">' . $addstr .'</a>';
4  lib/simpletest/testcompletionlib.php
@@ -46,11 +46,11 @@ function valid() {
46 46
     }
47 47
 
48 48
     function close() {
49  
-        $closed=true;
  49
+        $this->closed=true;
50 50
     }
51 51
 
52 52
     function was_closed() {
53  
-        return $closed;
  53
+        return $this->closed;
54 54
     }
55 55
 }
56 56
 
706  lib/simpletest/testcsslib.php
... ...
@@ -0,0 +1,706 @@
  1
+<?php
  2
+// This file is part of Moodle - http://moodle.org/
  3
+//
  4
+// Moodle is free software: you can redistribute it and/or modify
  5
+// it under the terms of the GNU General Public License as published by
  6
+// the Free Software Foundation, either version 3 of the License, or
  7
+// (at your option) any later version.
  8
+//
  9
+// Moodle is distributed in the hope that it will be useful,
  10
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
  11
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12
+// GNU General Public License for more details.
  13
+//
  14
+// You should have received a copy of the GNU General Public License
  15
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16
+
  17
+/**
  18
+ * This file contains the unittests for the css optimiser in csslib.php
  19
+ *
  20
+ * @package core_css
  21
+ * @category css
  22
+ * @copyright 2012 Sam Hemelryk
  23
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  24
+ */
  25
+
  26
+if (!defined('MOODLE_INTERNAL')) {
  27
+    die('Direct access to this script is forbidden.');    ///  It must be included from a Moodle page
  28
+}
  29
+require_once($CFG->libdir . '/csslib.php');
  30
+
  31
+
  32
+/**
  33
+ * CSS optimiser test class
  34
+ *
  35
+ * @package core_css
  36
+ * @category css
  37
+ * @copyright 2012 Sam Hemelryk
  38
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  39
+ */
  40
+class css_optimiser_test extends UnitTestCase {
  41
+
  42
+    /**
  43
+     * Sets up the test class
  44
+     */
  45
+    public function setUp() {
  46
+        global $CFG;
  47
+        parent::setUp();
  48
+        // We need to disable these if they are enabled to that we can predict
  49
+        // the output.
  50
+        $CFG->cssoptimiserstats = false;
  51
+        $CFG->cssoptimiserpretty = false;
  52
+    }
  53
+
  54
+    /**
  55
+     * Test the process method
  56
+     */
  57
+    public function test_process() {
  58
+        $optimiser = new css_optimiser;
  59
+
  60
+        $this->check_background($optimiser);
  61
+        $this->check_borders($optimiser);
  62
+        $this->check_colors($optimiser);
  63
+        $this->check_margins($optimiser);
  64
+        $this->check_padding($optimiser);
  65
+        $this->check_widths($optimiser);
  66
+
  67
+        $this->try_broken_css_found_in_moodle($optimiser);
  68
+        $this->try_invalid_css_handling($optimiser);
  69
+        $this->try_bulk_processing($optimiser);
  70
+        $this->try_break_things($optimiser);
  71
+    }
  72
+
  73
+    /**
  74
+     * Background colour tests
  75
+     * @param css_optimiser $optimiser
  76
+     */
  77
+    protected function check_background(css_optimiser $optimiser) {
  78
+
  79
+        $cssin = '.test {background-color: #123456;}';
  80
+        $cssout = '.test{background:#123456;}';
  81
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  82
+
  83
+        $cssin = '.test {background-image: url(\'test.png\');}';
  84
+        $cssout = '.test{background-image:url(\'test.png\');}';
  85
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  86
+
  87
+        $cssin = '.test {background: #123456 url(\'test.png\') no-repeat top left;}';
  88
+        $cssout = '.test{background:#123456 url(\'test.png\') no-repeat top left;}';
  89
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  90
+
  91
+        $cssin = '.test {background: url(\'test.png\') no-repeat top left;}.test{background-position: bottom right}.test {background-color:#123456;}';
  92
+        $cssout = '.test{background:#123456 url(\'test.png\') no-repeat bottom right;}';
  93
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  94
+
  95
+        $cssin = '.test {background: url(   \'test.png\'    )}.test{background: bottom right}.test {background:#123456;}';
  96
+        $cssout = '.test{background-image:url(\'test.png\');background-position:bottom right;background-color:#123456;}';
  97
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  98
+
  99
+        $cssin = '.test {background-color: #123456;background-repeat: repeat-x; background-position: 100% 0%;}';
  100
+        $cssout = '.test{background-color:#123456;background-repeat:repeat-x;background-position:100% 0%;}';
  101
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  102
+
  103
+        $cssin = '.tree_item.branch {background-image: url([[pix:t/expanded]]);background-position: 0 10%;background-repeat: no-repeat;}
  104
+                  .tree_item.branch.navigation_node {background-image:none;padding-left:0;}';
  105
+        $cssout = '.tree_item.branch{background:url([[pix:t/expanded]]) no-repeat 0 10%;} .tree_item.branch.navigation_node{background-image:none;padding-left:0;}';
  106
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  107
+
  108
+        $cssin = '.block_tree .tree_item.emptybranch {background-image: url([[pix:t/collapsed_empty]]);background-position: 0% 5%;background-repeat: no-repeat;}
  109
+                  .block_tree .collapsed .tree_item.branch {background-image: url([[pix:t/collapsed]]);}';
  110
+        $cssout = '.block_tree .tree_item.emptybranch{background:url([[pix:t/collapsed_empty]]) no-repeat 0% 5%;} .block_tree .collapsed .tree_item.branch{background-image:url([[pix:t/collapsed]]);}';
  111
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  112
+    }
  113
+
  114
+    /**
  115
+     * Border tests
  116
+     * @param css_optimiser $optimiser
  117
+     */
  118
+    protected function check_borders(css_optimiser $optimiser) {
  119
+        $cssin = '.test {border: 1px solid #654321} .test {border-bottom-color: #123456}';
  120
+        $cssout = '.test{border:1px solid;border-color:#654321 #654321 #123456;}';
  121
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  122
+
  123
+        $cssin = '.one {border:1px solid red;}';
  124
+        $cssout = '.one{border:1px solid #FF0000;}';
  125
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  126
+
  127
+        $cssin = '.one {border:1px solid;} .one {border:2px dotted #DDD;}';
  128
+        $cssout = '.one{border:2px dotted #DDDDDD;}';
  129
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  130
+
  131
+        $cssin = '.one {border:2px dotted #DDD;}.one {border:1px solid;} ';
  132
+        $cssout = '.one{border:1px solid #DDDDDD;}';
  133
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  134
+
  135
+        $cssin = '.one, .two {border:1px solid red;}';
  136
+        $cssout = ".one, .two{border:1px solid #FF0000;}";
  137
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  138
+
  139
+        $cssin = '.one, .two {border:0px;}';
  140
+        $cssout = ".one, .two{border-width:0;}";
  141
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  142
+
  143
+        $cssin = '.one, .two {border-top: 5px solid white;}';
  144
+        $cssout = ".one, .two{border-top:5px solid #FFFFFF;}";
  145
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  146
+
  147
+        $cssin = '.one {border:1px solid red;} .two {border:1px solid red;}';
  148
+        $cssout = ".one, .two{border:1px solid #FF0000;}";
  149
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  150
+
  151
+        $cssin = '.one {border:1px solid red;width:20px;} .two {border:1px solid red;height:20px;}';
  152
+        $cssout = ".one{width:20px;border:1px solid #FF0000;} .two{height:20px;border:1px solid #FF0000;}";
  153
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  154
+
  155
+        $cssin = '.test {border: 1px solid #123456;} .test {border-color: #654321}';
  156
+        $cssout = '.test{border:1px solid #654321;}';
  157
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  158
+
  159
+        $cssin = '.test {border-width: 1px; border-style: solid; border-color: #123456;}';
  160
+        $cssout = '.test{border:1px solid #123456;}';
  161
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  162
+
  163
+        $cssin = '.test {border:1px solid #123456;border-top:2px dotted #654321;}';
  164
+        $cssout = '.test{border:1px solid #123456;border-top:2px dotted #654321;}';
  165
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  166
+
  167
+        $cssin = '.test {border:1px solid #123456;border-left:2px dotted #654321;}';
  168
+        $cssout = '.test{border:1px solid #123456;border-left:2px dotted #654321;}';
  169
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  170
+
  171
+        $cssin = '.test {border-left:2px dotted #654321;border:1px solid #123456;}';
  172
+        $cssout = '.test{border:1px solid #123456;}';
  173
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  174
+
  175
+        $cssin = '.test {border:1px solid;border-top-color:#123456;}';
  176
+        $cssout = '.test{border:1px solid;border-top-color:#123456;}';
  177
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  178
+
  179
+        $cssin = '.test {border:1px solid;border-top-color:#111; border-bottom-color: #222;border-left-color: #333;}';
  180
+        $cssout = '.test{border:1px solid;border-top-color:#111;border-bottom-color:#222;border-left-color:#333;}';
  181
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  182
+
  183
+        $cssin = '.test {border:1px solid;border-top-color:#111; border-bottom-color: #222;border-left-color: #333;border-right-color:#444;}';
  184
+        $cssout = '.test{border:1px solid;border-color:#111 #444 #222 #333;}';
  185
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  186
+
  187
+        $cssin = '.generaltable .cell {border-color:#EEEEEE;} .generaltable .cell {border-width: 1px;border-style: solid;}';
  188
+        $cssout = '.generaltable .cell{border:1px solid #EEEEEE;}';
  189
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  190
+
  191
+        $cssin = '#page-admin-roles-override .rolecap {border:none;border-bottom:1px solid #CECECE;}';
  192
+        $cssout = '#page-admin-roles-override .rolecap{border-top:0;border-right:0;border-bottom:1px solid #CECECE;border-left:0;}';
  193
+        $this->assertEqual($cssout, $optimiser->process($cssin));
  194
+    }
  195
+