Merge branch 'MDL-45650_master' of https://github.com/markn86/moodle
authorSam Hemelryk <sam@moodle.com>
Mon, 26 May 2014 01:59:08 +0000 (13:59 +1200)
committerSam Hemelryk <sam@moodle.com>
Mon, 26 May 2014 01:59:08 +0000 (13:59 +1200)
268 files changed:
admin/category.php
admin/index.php
admin/lib.php
admin/roles/assign.php
admin/roles/manage.php
admin/tool/behat/index.php
admin/tool/log/store/legacy/classes/log/store.php
auth/mnet/db/mnet.php
availability/classes/condition.php
availability/classes/frontend.php
availability/classes/info.php
availability/classes/info_module.php
availability/classes/info_section.php
availability/classes/tree.php
availability/classes/tree_node.php
availability/condition/completion/classes/condition.php
availability/condition/date/classes/condition.php
availability/condition/date/classes/frontend.php
availability/condition/grade/classes/condition.php
availability/condition/group/classes/condition.php
availability/condition/grouping/classes/condition.php
availability/condition/profile/classes/condition.php
availability/condition/profile/tests/behat/availability_profile.feature
availability/condition/profile/tests/condition_test.php
availability/condition/profile/yui/build/moodle-availability_profile-form/moodle-availability_profile-form-debug.js
availability/condition/profile/yui/build/moodle-availability_profile-form/moodle-availability_profile-form-min.js
availability/condition/profile/yui/build/moodle-availability_profile-form/moodle-availability_profile-form.js
availability/condition/profile/yui/src/form/js/form.js
backup/backup.class.php
backup/util/helper/backup_general_helper.class.php
badges/award.php
blocks/community/db/upgrade.php
blocks/completionstatus/db/upgrade.php
blocks/course_overview/renderer.php
blocks/course_summary/db/upgrade.php
blocks/course_summary/tests/behat/block_course_summary_course.feature
blocks/course_summary/tests/behat/block_course_summary_frontpage.feature
blocks/glossary_random/tests/behat/glossary_random.feature [new file with mode: 0644]
blocks/glossary_random/tests/behat/glossary_random_frontpage.feature [new file with mode: 0644]
blocks/html/db/upgrade.php
blocks/html/tests/behat/configuring_html_block.feature [new file with mode: 0644]
blocks/html/tests/behat/course_block.feature [new file with mode: 0644]
blocks/html/tests/behat/multiple_instances.feature [new file with mode: 0644]
blocks/navigation/block_navigation.php
blocks/navigation/db/upgrade.php
blocks/navigation/edit_form.php
blocks/navigation/lang/en/block_navigation.php
blocks/navigation/renderer.php
blocks/navigation/tests/behat/view_my_courses.feature
blocks/section_links/db/upgrade.php
blocks/section_links/renderer.php
blocks/selfcompletion/db/upgrade.php
blocks/settings/block_settings.php
blocks/settings/db/upgrade.php
blocks/settings/edit_form.php
blocks/settings/lang/en/block_settings.php
blocks/tests/behat/behat_blocks.php
blocks/tests/behat/configure_block_throughout_site.feature
blocks/tests/behat/manage_blocks.feature
blocks/tests/behat/restrict_available_blocks.feature
blocks/tests/behat/return_block_original_state.feature
cache/classes/definition.php
cache/classes/factory.php
cache/classes/helper.php
cache/classes/interfaces.php
cache/classes/loaders.php
cache/classes/store.php
cache/tests/cache_test.php
comment/lib.php
course/format/lib.php
course/format/social/lib.php
course/format/topics/lib.php
course/format/weeks/lib.php
course/lib.php
course/report/lib.php
course/switchrole.php
course/tests/behat/behat_course.php
course/tests/behat/max_number_sections.feature
enrol/mnet/db/mnet.php
grade/querylib.php
grade/tests/querylib_test.php
group/autogroup_form.php
install/lang/de/install.php
install/lang/oc_lnc/langconfig.php [new file with mode: 0644]
install/lang/oc_lnc/moodle.php [new file with mode: 0644]
lang/en/availability.php
lang/en/moodle.php
lib/accesslib.php
lib/ajax/getnavbranch.php
lib/ajax/getsiteadminbranch.php
lib/authlib.php
lib/behat/classes/behat_selectors.php
lib/classes/event/message_viewed.php
lib/classes/event/user_enrolment_created.php
lib/classes/event/user_profile_viewed.php
lib/classes/plugininfo/availability.php
lib/classes/task/delete_unconfirmed_users_task.php
lib/classes/task/file_temp_cleanup_task.php
lib/classes/text.php
lib/csslib.php
lib/db/upgrade.php
lib/dml/moodle_database.php
lib/dml/mssql_native_moodle_database.php
lib/dml/mysqli_native_moodle_database.php
lib/dml/pgsql_native_moodle_database.php
lib/dml/sqlsrv_native_moodle_database.php
lib/editor/atto/lib.php
lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button-debug.js
lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button-min.js
lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button.js
lib/editor/atto/plugins/collapse/yui/src/button/js/button.js
lib/editor/atto/plugins/html/yui/build/moodle-atto_html-button/moodle-atto_html-button-debug.js
lib/editor/atto/plugins/html/yui/build/moodle-atto_html-button/moodle-atto_html-button-min.js
lib/editor/atto/plugins/html/yui/build/moodle-atto_html-button/moodle-atto_html-button.js
lib/editor/atto/plugins/html/yui/src/button/js/button.js
lib/editor/atto/plugins/image/styles.css
lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-debug.js
lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-min.js
lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button.js
lib/editor/atto/plugins/image/yui/src/button/js/button.js
lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button-debug.js
lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button-min.js
lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button.js
lib/editor/atto/plugins/undo/yui/src/button/js/button.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js
lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js
lib/editor/atto/yui/build/moodle-editor_atto-plugin/moodle-editor_atto-plugin-debug.js
lib/editor/atto/yui/build/moodle-editor_atto-plugin/moodle-editor_atto-plugin-min.js
lib/editor/atto/yui/build/moodle-editor_atto-plugin/moodle-editor_atto-plugin.js
lib/editor/atto/yui/src/editor/js/clean.js
lib/editor/atto/yui/src/editor/js/editor-plugin-buttons.js
lib/editor/atto/yui/src/editor/js/editor.js
lib/editor/atto/yui/src/editor/js/selection.js
lib/external/externallib.php
lib/externallib.php
lib/filelib.php
lib/filestorage/file_storage.php
lib/filterlib.php
lib/form/text.php
lib/google/curlio.php
lib/gradelib.php
lib/licenselib.php
lib/moodlelib.php
lib/navigationlib.php
lib/outputrenderers.php
lib/outputrequirementslib.php
lib/pagelib.php
lib/pdflib.php
lib/phpunit/classes/util.php
lib/plagiarismlib.php
lib/testing/generator/data_generator.php
lib/testing/generator/repository_generator.php
lib/tests/behat/behat_general.php
lib/tests/behat/behat_navigation.php
lib/tests/cronlib_test.php
lib/tests/csslib_test.php
lib/tests/moodlelib_test.php
lib/upgradelib.php
lib/weblib.php
lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception-debug.js
lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception-min.js
lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception.js
lib/yui/build/moodle-core-notification-confirm/moodle-core-notification-confirm-debug.js
lib/yui/build/moodle-core-notification-confirm/moodle-core-notification-confirm-min.js
lib/yui/build/moodle-core-notification-confirm/moodle-core-notification-confirm.js
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-debug.js
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-min.js
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue.js
lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-debug.js
lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-min.js
lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception.js
lib/yui/src/notification/js/ajaxexception.js
lib/yui/src/notification/js/confirm.js
lib/yui/src/notification/js/dialogue.js
lib/yui/src/notification/js/exception.js
message/externallib.php
message/lib.php
message/output/email/lang/en/message_email.php
message/output/email/settings.php
message/tests/events_test.php
mod/assign/lib.php
mod/assign/locallib.php
mod/assign/submission/onlinetext/locallib.php
mod/assign/tests/behat/prevent_submission_changes.feature
mod/chat/lib.php
mod/forum/classes/observer.php
mod/forum/db/upgrade.php
mod/forum/index.php
mod/forum/lib.php
mod/forum/mod_form.php
mod/forum/unsubscribeall.php
mod/forum/version.php
mod/glossary/index.php
mod/lesson/pagetypes/multichoice.php
mod/lesson/styles.css
mod/quiz/accessmanager.php
mod/quiz/accessrule/accessrulebase.php
mod/quiz/accessrule/upgrade.txt
mod/quiz/cronlib.php
mod/quiz/db/upgrade.php
mod/quiz/lib.php
mod/quiz/report/attemptsreport_options.php
mod/quiz/report/overview/overview_options.php
plagiarism/lib.php
portfolio/mahara/db/mnet.php
portfolio/mahara/lib.php
portfolio/mahara/preconfig.php
portfolio/mahara/version.php
question/classes/statistics/responses/analysis_for_class.php
question/engine/tests/questionusage_autosave_test.php
question/type/calculated/lib.php
question/type/calculatedmulti/lib.php
question/type/calculatedsimple/lib.php
question/type/essay/lib.php
question/type/match/lib.php
question/type/multichoice/lib.php
question/type/multichoice/question.php
question/type/numerical/lib.php
question/type/randomsamatch/lib.php
question/type/shortanswer/lib.php
question/type/truefalse/lib.php
repository/alfresco/lib.php
repository/boxnet/lib.php
repository/coursefiles/lib.php
repository/draftfiles_manager.php
repository/dropbox/lib.php
repository/dropbox/locallib.php
repository/equella/callback.php
repository/equella/lib.php
repository/equella/version.php
repository/filepicker.php
repository/filesystem/lib.php
repository/flickr/lib.php
repository/flickr_public/lib.php
repository/googledocs/lib.php
repository/lib.php
repository/local/lib.php
repository/manage_instances.php
repository/merlot/lib.php
repository/picasa/lib.php
repository/recent/lib.php
repository/repository_ajax.php
repository/repository_callback.php
repository/s3/lib.php
repository/upload/lib.php
repository/url/lib.php
repository/user/lib.php
repository/webdav/lib.php
repository/wikimedia/lib.php
repository/youtube/lib.php
theme/base/style/core.css
theme/base/style/filemanager.css
theme/bootstrapbase/less/moodle/admin.less
theme/bootstrapbase/less/moodle/filemanager.less
theme/bootstrapbase/less/moodle/forms.less
theme/bootstrapbase/less/moodle/modules.less
theme/bootstrapbase/less/moodle/responsive.less
theme/bootstrapbase/style/moodle.css
theme/more/less/moodle.less
user/filters/cohort.php
user/profile/field/menu/field.class.php
user/profile/lib.php
user/tests/profilelib_test.php [new file with mode: 0644]
user/view.php
version.php
webservice/soap/locallib.php
webservice/xmlrpc/locallib.php

index 1d68207..fdda580 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * This file is used to display a categories sub categories, external pages, and settings.
  *
- * @since      2.3
+ * @since      Moodle 2.3
  * @package    admin
  * @copyright  2011 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 4947c5e..aaa530a 100644 (file)
@@ -378,9 +378,6 @@ if (!$cache and moodle_needs_upgrading()) {
     if (!$PAGE->headerprinted) {
         // means core upgrade or installation was not already done
 
-        /** @var core_admin_renderer $output */
-        $output = $PAGE->get_renderer('core', 'admin');
-
         if (!$confirmplugins) {
             $strplugincheck = get_string('plugincheck');
 
@@ -398,6 +395,9 @@ if (!$cache and moodle_needs_upgrading()) {
                 redirect($PAGE->url);
             }
 
+            /** @var core_admin_renderer $output */
+            $output = $PAGE->get_renderer('core', 'admin');
+
             $deployer = \core\update\deployer::instance();
             if ($deployer->enabled()) {
                 $deployer->initialize($PAGE->url, $PAGE->url);
@@ -421,6 +421,8 @@ if (!$cache and moodle_needs_upgrading()) {
         // Make sure plugin dependencies are always checked.
         $failed = array();
         if (!core_plugin_manager::instance()->all_plugins_ok($version, $failed)) {
+            /** @var core_admin_renderer $output */
+            $output = $PAGE->get_renderer('core', 'admin');
             $reloadurl = new moodle_url('/admin/index.php', array('cache' => 0));
             echo $output->unsatisfied_dependencies_page($version, $failed, $reloadurl);
             die();
index fbb9997..c9ddefa 100644 (file)
@@ -18,7 +18,7 @@
 /**
  * This file contains functions used by the admin pages
  *
- * @since 2.1
+ * @since Moodle 2.1
  * @package admin
  * @copyright 2011 Andrew Davis
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 421eca2..78b496a 100644 (file)
@@ -176,7 +176,7 @@ if ($roleid) {
     // Show UI for assigning a particular role to users.
     // Print a warning if we are assigning system roles.
     if ($context->contextlevel == CONTEXT_SYSTEM) {
-        echo $OUTPUT->box(get_string('globalroleswarning', 'core_role'));
+        echo $OUTPUT->notification(get_string('globalroleswarning', 'core_role'));
     }
 
     // Print the form.
@@ -251,7 +251,7 @@ if ($roleid) {
 
     // Print a warning if we are assigning system roles.
     if ($context->contextlevel == CONTEXT_SYSTEM) {
-        echo $OUTPUT->box(get_string('globalroleswarning', 'core_role'));
+        echo $OUTPUT->notification(get_string('globalroleswarning', 'core_role'));
     }
 
     // Print instruction.
index e3e094a..6cd63ab 100644 (file)
@@ -75,7 +75,8 @@ switch ($action) {
             $a->id = $roleid;
             $a->name = $roles[$roleid]->name;
             $a->shortname = $roles[$roleid]->shortname;
-            $a->count = $DB->count_records('role_assignments', array('roleid'=>$roleid));
+            $a->count = $DB->count_records_select('role_assignments',
+                'roleid = ?', array($roleid), 'COUNT(DISTINCT userid)');
 
             $formcontinue = new single_button(new moodle_url($baseurl, $optionsyes), get_string('yes'));
             $formcancel = new single_button(new moodle_url($baseurl), get_string('no'), 'get');
index f68ec13..5e71bdf 100644 (file)
@@ -27,6 +27,11 @@ require_once($CFG->libdir.'/adminlib.php');
 require_once($CFG->dirroot . '/' . $CFG->admin . '/tool/behat/locallib.php');
 require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
 
+// This page usually takes an exceedingly long time to load, so we need to
+// increase the time limit. At present it takes about a minute on some
+// systems, but let's allow room for expansion.
+core_php_time_limit::raise(300);
+
 $filter = optional_param('filter', '', PARAM_ALPHANUMEXT);
 $type = optional_param('type', false, PARAM_ALPHAEXT);
 $component = optional_param('component', '', PARAM_ALPHAEXT);
index eb75d4b..48d561e 100644 (file)
@@ -185,6 +185,11 @@ class store implements \tool_log\log\store, \core\log\sql_select_reader {
         // database so that it doesn't cause a DB error. Log a warning so that
         // developers can avoid doing things which are likely to cause this on a
         // routine basis.
+        if (\core_text::strlen($action) > 40) {
+            $action = \core_text::substr($action, 0, 37) . '...';
+            debugging('Warning: logged very long action', DEBUG_DEVELOPER);
+        }
+
         if (!empty($info) && \core_text::strlen($info) > 255) {
             $info = \core_text::substr($info, 0, 252) . '...';
             debugging('Warning: logged very long info', DEBUG_DEVELOPER);
index 8a371d3..262e6b7 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * This file contains the mnet services for the mnet authentication plugin
  *
- * @since 2.0
+ * @since Moodle 2.0
  * @package auth_mnet
  * @copyright 2010 Penny Leach
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 5685b5a..e10b0bd 100644 (file)
@@ -180,7 +180,7 @@ abstract class condition extends tree_node {
      *
      * Default implementation returns false.
      *
-     * @param stdClass $course Moodle course object
+     * @param \stdClass $course Moodle course object
      * @param int $cmid ID of activity whose completion value is considered
      * @return boolean True if the availability of something else may rely on it
      */
index ea7b012..fba731c 100644 (file)
@@ -46,7 +46,7 @@ abstract class frontend {
      *
      * Default returns true.
      *
-     * @param stdClass $course Course object
+     * @param \stdClass $course Course object
      * @param \cm_info $cm Course-module currently being edited (null if none)
      * @param \section_info $section Section currently being edited (null if none)
      */
@@ -73,7 +73,7 @@ abstract class frontend {
      *
      * Default returns no parameters.
      *
-     * @param stdClass $course Course object
+     * @param \stdClass $course Course object
      * @param \cm_info $cm Course-module currently being edited (null if none)
      * @param \section_info $section Section currently being edited (null if none)
      * @return array Array of parameters for the JavaScript function
@@ -95,7 +95,7 @@ abstract class frontend {
     /**
      * Includes JavaScript for the main system and all plugins.
      *
-     * @param stdClass $course Course object
+     * @param \stdClass $course Course object
      * @param \cm_info $cm Course-module currently being edited (null if none)
      * @param \section_info $section Section currently being edited (null if none)
      */
index a335d38..884151b 100644 (file)
@@ -34,7 +34,7 @@ defined('MOODLE_INTERNAL') || die();
  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 abstract class info {
-    /** @var stdClass Course */
+    /** @var \stdClass Course */
     protected $course;
 
     /** @var \course_modinfo Modinfo (available only during some functions) */
@@ -52,10 +52,10 @@ abstract class info {
     /**
      * Constructs with item details.
      *
-     * @param stdClass $course Course object
+     * @param \stdClass $course Course object
      * @param int $visible Value of visible flag (eye icon)
      * @param string $availability Availability definition (JSON format) or null
-     * @throws coding_exception If data is not valid JSON format
+     * @throws \coding_exception If data is not valid JSON format
      */
     public function __construct($course, $visible, $availability) {
         // Set basic values.
@@ -67,7 +67,7 @@ abstract class info {
     /**
      * Obtains the course associated with this availability information.
      *
-     * @return stdClass Moodle course object
+     * @return \stdClass Moodle course object
      */
     public function get_course() {
         return $this->course;
@@ -128,7 +128,7 @@ abstract class info {
      * @param string $availability Availability string in JSON format
      * @param boolean $lax If true, throw exceptions only for invalid structure
      * @return tree Availability tree
-     * @throws coding_exception If data is not valid JSON format
+     * @throws \coding_exception If data is not valid JSON format
      */
     protected function decode_availability($availability, $lax) {
         // Decode JSON data.
@@ -306,7 +306,7 @@ abstract class info {
      *
      * @param string $restoreid Restore identifier
      * @param int $courseid Target course id
-     * @param base_logger $logger Logger for any warnings
+     * @param \base_logger $logger Logger for any warnings
      */
     public function update_after_restore($restoreid, $courseid, \base_logger $logger) {
         $tree = $this->get_availability_tree();
@@ -342,7 +342,7 @@ abstract class info {
      * function does that for the conditional availability data for all
      * modules and sections on the course.
      *
-     * @param int|stdClass $courseorid Course id or object
+     * @param int|\stdClass $courseorid Course id or object
      * @param string $table Table name e.g. 'course_modules'
      * @param int $oldid Previous ID
      * @param int $newid New ID
@@ -407,7 +407,7 @@ abstract class info {
      * groupmembersonly field for modules. This is off by default because
      * we are not yet moving the groupmembersonly option into this new API.
      *
-     * @param stdClass $rec Object possibly containing legacy fields
+     * @param \stdClass $rec Object possibly containing legacy fields
      * @param bool $section True if this is a section
      * @param bool $modgroupmembersonly True if groupmembersonly is converted for mods
      * @return string|null New availability value or null if none
@@ -468,7 +468,7 @@ abstract class info {
      * that it has an AND tree with one or more conditions.
      *
      * @param string|null $availability Current availability conditions
-     * @param stdClass $rec Object containing information from old table
+     * @param \stdClass $rec Object containing information from old table
      * @param bool $show True if 'show' option should be enabled
      * @return string New availability conditions
      */
@@ -501,7 +501,7 @@ abstract class info {
      * that it has an AND tree with one or more conditions.
      *
      * @param string|null $availability Current availability conditions
-     * @param stdClass $rec Object containing information from old table
+     * @param \stdClass $rec Object containing information from old table
      * @param bool $show True if 'show' option should be enabled
      * @return string New availability conditions
      */
@@ -598,8 +598,8 @@ abstract class info {
      * object.
      *
      * @param string $info Info string
-     * @param int|stdClass $courseorid
-     * @return Correctly formatted info string
+     * @param int|\stdClass $courseorid
+     * @return string Correctly formatted info string
      */
     public static function format_info($info, $courseorid) {
         // Don't waste time if there are no special tags.
@@ -624,7 +624,7 @@ abstract class info {
      * JS (using the non-JS version instead, which causes a page reload) if a
      * completion tickbox value may affect a conditional activity.
      *
-     * @param stdClass $course Moodle course object
+     * @param \stdClass $course Moodle course object
      * @param int $cmid Course-module id
      * @return bool True if this is used in a condition, false otherwise
      */
index 139812c..af4ae5f 100644 (file)
@@ -63,7 +63,7 @@ class info_module extends info {
     /**
      * Gets the course-module object. Intended for use by conditions.
      *
-     * @return cm_info Course module
+     * @return \cm_info Course module
      */
     public function get_course_module() {
         return $this->cm;
@@ -130,11 +130,11 @@ class info_module extends info {
      * disabled, and you supply a $cm object with necessary fields, and you
      * don't check course access.
      *
-     * @param int|stdClass|cm_info $cmorid Object or id representing activity
+     * @param int|\stdClass|\cm_info $cmorid Object or id representing activity
      * @param int $userid User id (0 = current user)
      * @param bool $checkcourse If true, checks whether the user has course access
      * @return bool True if the activity is visible to the specified user
-     * @throws moodle_exception If the cmid doesn't exist
+     * @throws \moodle_exception If the cmid doesn't exist
      */
     public static function is_user_visible($cmorid, $userid = 0, $checkcourse = true) {
         global $USER, $DB, $CFG;
index 777c46a..4f98522 100644 (file)
@@ -65,7 +65,7 @@ class info_section extends info {
     /**
      * Gets the section object. Intended for use by conditions.
      *
-     * @return section_info Section
+     * @return \section_info Section
      */
     public function get_section() {
         return $this->section;
index 964af4f..f73ba2d 100644 (file)
@@ -128,11 +128,11 @@ class tree extends tree_node {
      *    coding_exception (if $lax is false).
      *
      * @see decode_availability
-     * @param stdClass $structure Structure (decoded from JSON)
+     * @param \stdClass $structure Structure (decoded from JSON)
      * @param boolean $lax If true, throw exceptions only for invalid structure
      * @param boolean $root If true, this is the root tree
      * @return tree Availability tree
-     * @throws coding_exception If data is not valid structure
+     * @throws \coding_exception If data is not valid structure
      */
     public function __construct($structure, $lax = false, $root = true) {
         $this->root = $root;
@@ -389,12 +389,12 @@ class tree extends tree_node {
      * for display to staff.
      *
      * @param info $info Information about location of condition tree
-     * @throws coding_exception If you call on a non-root tree
+     * @throws \coding_exception If you call on a non-root tree
      * @return string HTML data (empty string if none)
      */
     public function get_full_information(info $info) {
         if (!$this->root) {
-            throw new coding_exception('Only supported on root item');
+            throw new \coding_exception('Only supported on root item');
         }
         return $this->get_full_information_recursive(false, $info, null, true);
     }
@@ -406,12 +406,12 @@ class tree extends tree_node {
      *
      * @param info $info Information about location of condition tree
      * @param result $result Result object
-     * @throws coding_exception If you call on a non-root tree
+     * @throws \coding_exception If you call on a non-root tree
      * @return string HTML data (empty string if none)
      */
     public function get_result_information(info $info, result $result) {
         if (!$this->root) {
-            throw new coding_exception('Only supported on root item');
+            throw new \coding_exception('Only supported on root item');
         }
         return $this->get_full_information_recursive(false, $info, $result, true);
     }
@@ -530,7 +530,7 @@ class tree extends tree_node {
                 $negative = true;
                 break;
             default:
-                throw new coding_exception('Unknown operator');
+                throw new \coding_exception('Unknown operator');
         }
         switch($this->op) {
             case self::OP_AND:
@@ -542,7 +542,7 @@ class tree extends tree_node {
                 $andoperator = false;
                 break;
             default:
-                throw new coding_exception('Unknown operator');
+                throw new \coding_exception('Unknown operator');
         }
 
         // Select NOT (or not) for children. It flips if this is a 'not' group.
index 2e61c7f..22dc48d 100644 (file)
@@ -78,7 +78,7 @@ abstract class tree_node {
     /**
      * Saves tree data back to a structure object.
      *
-     * @return stdClass Structure object (ready to be made into JSON format)
+     * @return \stdClass Structure object (ready to be made into JSON format)
      */
     public abstract function save();
 
@@ -152,11 +152,11 @@ abstract class tree_node {
      * @param \core_availability\info $info Item we're checking
      * @param capability_checker $checker
      * @return array Filtered version of input array
-     * @throws coding_exception If called on a condition that doesn't apply to user lists
+     * @throws \coding_exception If called on a condition that doesn't apply to user lists
      */
     public function filter_user_list(array $users, $not,
             \core_availability\info $info, capability_checker $checker) {
-        throw new coding_exception('Not implemented (do not call unless '.
+        throw new \coding_exception('Not implemented (do not call unless '.
                 'is_applied_to_user_lists is true)');
     }
 }
index d44ff2f..82d99da 100644 (file)
@@ -48,8 +48,8 @@ class condition extends \core_availability\condition {
     /**
      * Constructor.
      *
-     * @param stdClass $structure Data structure from JSON decode
-     * @throws coding_exception If invalid data structure.
+     * @param \stdClass $structure Data structure from JSON decode
+     * @throws \coding_exception If invalid data structure.
      */
     public function __construct($structure) {
         // Get cmid.
@@ -212,7 +212,7 @@ class condition extends \core_availability\condition {
      * Used in course/lib.php because we need to disable the completion JS if
      * a completion value affects a conditional activity.
      *
-     * @param stdClass $course Moodle course object
+     * @param \stdClass $course Moodle course object
      * @param int $cmid Course-module id
      * @return bool True if this is used in a condition, false otherwise
      */
index c1b3bba..36191f9 100644 (file)
@@ -52,8 +52,8 @@ class condition extends \core_availability\condition {
     /**
      * Constructor.
      *
-     * @param stdClass $structure Data structure from JSON decode
-     * @throws coding_exception If invalid data structure.
+     * @param \stdClass $structure Data structure from JSON decode
+     * @throws \coding_exception If invalid data structure.
      */
     public function __construct($structure) {
         // Get direction.
index e1cba19..3af4172 100644 (file)
@@ -74,7 +74,7 @@ class frontend extends \core_availability\frontend {
      * Given a timestamp, obtains corresponding field values.
      *
      * @param int $time Timestamp
-     * @return stdClass Object with fields for year, month, day, hour, minute
+     * @return \stdClass Object with fields for year, month, day, hour, minute
      */
     public static function get_fields_from_time($time) {
         $calendartype = \core_calendar\type_factory::get_calendar_instance();
index 887fdbc..9ae6391 100644 (file)
@@ -46,8 +46,8 @@ class condition extends \core_availability\condition {
     /**
      * Constructor.
      *
-     * @param stdClass $structure Data structure from JSON decode
-     * @throws coding_exception If invalid data structure.
+     * @param \stdClass $structure Data structure from JSON decode
+     * @throws \coding_exception If invalid data structure.
      */
     public function __construct($structure) {
         // Get grade item id.
index f228b4d..96b5435 100644 (file)
@@ -43,8 +43,8 @@ class condition extends \core_availability\condition {
     /**
      * Constructor.
      *
-     * @param stdClass $structure Data structure from JSON decode
-     * @throws coding_exception If invalid data structure.
+     * @param \stdClass $structure Data structure from JSON decode
+     * @throws \coding_exception If invalid data structure.
      */
     public function __construct($structure) {
         // Get group id.
index 6020670..2df2fe1 100644 (file)
@@ -46,8 +46,8 @@ class condition extends \core_availability\condition {
     /**
      * Constructor.
      *
-     * @param stdClass $structure Data structure from JSON decode
-     * @throws coding_exception If invalid data structure.
+     * @param \stdClass $structure Data structure from JSON decode
+     * @throws \coding_exception If invalid data structure.
      */
     public function __construct($structure) {
         // Get grouping id.
index 4d22e4e..d5ca5ed 100644 (file)
@@ -73,8 +73,8 @@ class condition extends \core_availability\condition {
     /**
      * Constructor.
      *
-     * @param stdClass $structure Data structure from JSON decode
-     * @throws coding_exception If invalid data structure.
+     * @param \stdClass $structure Data structure from JSON decode
+     * @throws \coding_exception If invalid data structure.
      */
     public function __construct($structure) {
         // Get operator.
@@ -292,14 +292,23 @@ class condition extends \core_availability\condition {
      * Gets data about custom profile fields. Cached statically in current
      * request.
      *
+     * This only includes fields which can be tested by the system (those whose
+     * data is cached in $USER object) - basically doesn't include textarea type
+     * fields.
+     *
      * @return array Array of records indexed by shortname
      */
     public static function get_custom_profile_fields() {
-        global $DB;
+        global $DB, $CFG;
 
         if (self::$customprofilefields === null) {
-            self::$customprofilefields = $DB->get_records('user_info_field', null,
-                    'id ASC', 'shortname, id, name, defaultdata');
+            // Get fields and store them indexed by shortname.
+            require_once($CFG->dirroot . '/user/profile/lib.php');
+            $fields = profile_get_custom_fields(true);
+            self::$customprofilefields = array();
+            foreach ($fields as $field) {
+                self::$customprofilefields[$field->shortname] = $field;
+            }
         }
         return self::$customprofilefields;
     }
index e4335ed..79c41a1 100644 (file)
@@ -64,3 +64,52 @@ Feature: availability_profile
     # I see P1 but not P2.
     Then I should see "P1" in the "region-main" "region"
     And I should not see "P2" in the "region-main" "region"
+
+  @javascript
+  Scenario: Test with custom user profile field
+    # Add custom field.
+    Given I log in as "admin"
+    And I navigate to "User profile fields" node in "Site administration > Users > Accounts"
+    And I set the field "datatype" to "Text input"
+    And I set the following fields to these values:
+      | Short name | superfield  |
+      | Name       | Super field |
+    And I click on "Save changes" "button"
+
+    # Set field value for user.
+    And I navigate to "Browse list of users" node in "Site administration > Users > Accounts"
+    And I click on "a[title=Edit]" "css_element" in the "s@example.org" "table_row"
+    And I expand all fieldsets
+    And I set the field "Super field" to "Bananaman"
+    And I click on "Update profile" "button"
+
+    # Set Page activity which has requirement on this field.
+    And I am on homepage
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Page" to section "1"
+    And I set the following fields to these values:
+      | Name         | P1 |
+      | Description  | x  |
+      | Page content | x  |
+    And I expand all fieldsets
+    And I click on "Add restriction..." "button"
+    And I click on "User profile" "button"
+    And I set the following fields to these values:
+      | User profile field       | Super field |
+      | Value to compare against | Bananaman   |
+    And I click on ".availability-item .availability-eye img" "css_element"
+    And I click on "Save and return to course" "button"
+
+    # Edit it again and check the setting still works.
+    When I follow "P1"
+    And I navigate to "Edit settings" node in "Page module administration"
+    And I expand all fieldsets
+    Then the field "User profile field" matches value "Super field"
+    And the field "Value to compare against" matches value "Bananaman"
+
+    # Log out and back in as student. Should be able to see activity.
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    Then I should see "P1" in the "region-main" "region"
index d81d951..8b2619a 100644 (file)
@@ -317,6 +317,29 @@ class availability_profile_condition_testcase extends advanced_testcase {
         $this->assertTrue($cond->is_available(false, $info, true, $user->id));
     }
 
+    /**
+     * Tests what happens with custom fields that are text areas. These should
+     * not be offered in the menu because their data is not included in user
+     * object
+     */
+    public function test_custom_textarea_field() {
+        global $USER, $SITE, $DB;
+        $this->setAdminUser();
+        $info = new \core_availability\mock_info();
+
+        // Add custom textarea type.
+        $DB->insert_record('user_info_field', array(
+                'shortname' => 'longtext', 'name' => 'Long text', 'categoryid' => 1,
+                'datatype' => 'textarea'));
+        $customfield = $DB->get_record('user_info_field',
+                array('shortname' => 'longtext'));
+
+        // The list of fields should include the text field added in setUp(),
+        // but should not include the textarea field added just now.
+        $fields = condition::get_custom_profile_fields();
+        $this->assertEquals(array('frogtype'), array_keys($fields));
+    }
+
     /**
      * Sets the custom profile field used for testing.
      *
index 47e4667..0973f47 100644 (file)
Binary files a/availability/condition/profile/yui/build/moodle-availability_profile-form/moodle-availability_profile-form-debug.js and b/availability/condition/profile/yui/build/moodle-availability_profile-form/moodle-availability_profile-form-debug.js differ
index a5addca..f0ab241 100644 (file)
Binary files a/availability/condition/profile/yui/build/moodle-availability_profile-form/moodle-availability_profile-form-min.js and b/availability/condition/profile/yui/build/moodle-availability_profile-form/moodle-availability_profile-form-min.js differ
index 47e4667..0973f47 100644 (file)
Binary files a/availability/condition/profile/yui/build/moodle-availability_profile-form/moodle-availability_profile-form.js and b/availability/condition/profile/yui/build/moodle-availability_profile-form/moodle-availability_profile-form.js differ
index ca3f3be..afc486e 100644 (file)
@@ -66,7 +66,7 @@ M.availability_profile.form.getNode = function(json) {
             node.one('select[name=field] > option[value=sf_' + json.sf + ']')) {
         node.one('select[name=field]').set('value', 'sf_' + json.sf);
     } else if (json.cf !== undefined &&
-            node.one('select[name=field] > option[value=cf_' + json.sf + ']')) {
+            node.one('select[name=field] > option[value=cf_' + json.cf + ']')) {
         node.one('select[name=field]').set('value', 'cf_' + json.cf);
     }
     if (json.op !== undefined &&
index 14864fe..7b56b05 100644 (file)
@@ -127,7 +127,7 @@ abstract class backup implements checksumable {
 
     // Version (to keep CFG->backup_version (and release) updated automatically)
     const VERSION = 2014051200;
-    const RELEASE = '2.7';
+    const RELEASE = '2.8';
 }
 
 /*
index 645f2e9..e84d2f6 100644 (file)
@@ -232,7 +232,7 @@ abstract class backup_general_helper extends backup_helper {
      *
      * @param string $filepath absolute path to the MBZ file.
      * @return stdClass containing information.
-     * @since 2.4
+     * @since Moodle 2.4
      */
     public static function get_backup_information_from_mbz($filepath) {
         global $CFG;
index 124e178..e288fe2 100644 (file)
@@ -120,7 +120,7 @@ if (count($acceptedroles) > 1) {
     }
 } else {
     // User has to be an admin or the one with the required role.
-    $users = get_role_users($acceptedroles[0], $context, false, 'u.id', 'u.id ASC');
+    $users = get_role_users($acceptedroles[0], $context, true, 'u.id', 'u.id ASC');
     $usersids = array_keys($users);
     if (!$isadmin && !in_array($USER->id, $usersids)) {
         echo $OUTPUT->header();
index 421b1f6..4216d29 100644 (file)
@@ -31,7 +31,7 @@
  * Please do not forget to use upgrade_set_timeout()
  * before any action that may take longer time to finish.
  *
- * @since 2.0
+ * @since Moodle 2.0
  * @package block_community
  * @copyright 2010 Jerome Mouneyrac
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 401040a..460c565 100644 (file)
@@ -31,7 +31,7 @@
  * Please do not forget to use upgrade_set_timeout()
  * before any action that may take longer time to finish.
  *
- * @since 2.0
+ * @since Moodle 2.0
  * @package block_completionstatus
  * @copyright 2012 Mark Nelson <markn@moodle.com>
  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 3efcd95..76ef098 100644 (file)
@@ -315,11 +315,11 @@ class block_course_overview_renderer extends plugin_renderer_base {
         $plural = 's';
         if ($msgcount > 0) {
             $output .= get_string('youhavemessages', 'block_course_overview', $msgcount);
-        } else {
-            $output .= get_string('youhavenomessages', 'block_course_overview');
             if ($msgcount == 1) {
                 $plural = '';
             }
+        } else {
+            $output .= get_string('youhavenomessages', 'block_course_overview');
         }
         $output .= html_writer::link(new moodle_url('/message/index.php'), get_string('message'.$plural, 'block_course_overview'));
         $output .= $this->output->box_end();
index 6e2b6f6..e4a6b9f 100644 (file)
@@ -31,7 +31,7 @@
  * Please do not forget to use upgrade_set_timeout()
  * before any action that may take longer time to finish.
  *
- * @since 2.0
+ * @since Moodle 2.0
  * @package block_course_summary
  * @copyright 2012 Mark Nelson <markn@moodle.com>
  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index b8758f3..bfe1e1b 100644 (file)
@@ -25,19 +25,19 @@ Feature: Course summary block used in a course
   Scenario: Student can view course summary
     When I log in as "student1"
     And I follow "Course 1"
-    Then "block_course_summary" "block" should exist
-    And I should see "Proved the course summary block works!" in the "block_course_summary" "block"
+    Then "Course/site summary" "block" should exist
+    And I should see "Proved the course summary block works!" in the "Course/site summary" "block"
 
   Scenario: Teacher can see an edit icon when edit mode is on and follow it to the course edit page
     When I log in as "teacher1"
     And I follow "Course 1"
     And I turn editing mode on
-    Then I should see "Proved the course summary block works!" in the "block_course_summary" "block"
-    And I click on "Edit" "link" in the "block_course_summary" "block"
+    Then I should see "Proved the course summary block works!" in the "Course/site summary" "block"
+    And I click on "Edit" "link" in the "Course/site summary" "block"
     Then I should see "Edit course settings" in the "h2" "css_element"
 
   Scenario: Teacher can not see edit icon when edit mode is off
     When I log in as "teacher1"
     And I follow "Course 1"
-    Then I should see "Proved the course summary block works!" in the "block_course_summary" "block"
-    And "Edit" "link" should not exist in the "block_course_summary" "block"
+    Then I should see "Proved the course summary block works!" in the "Course/site summary" "block"
+    And "Edit" "link" should not exist in the "Course/site summary" "block"
index 05e54e8..7c6373d 100644 (file)
@@ -15,19 +15,19 @@ Feature: Course summary block used on the frontpage
 
   Scenario: Guest can view site summary
     When I am on homepage
-    Then "block_course_summary" "block" should exist
-    And I should see "Proved the summary block works!" in the "block_course_summary" "block"
+    Then "Course/site summary" "block" should exist
+    And I should see "Proved the summary block works!" in the "Course/site summary" "block"
 
   Scenario: Admin can see an edit icon when edit mode is on and follow it to the front page settings
     When I log in as "admin"
     And I am on homepage
     And I follow "Turn editing on"
-    Then I should see "Proved the summary block works!" in the "block_course_summary" "block"
-    And I click on "Edit" "link" in the "block_course_summary" "block"
+    Then I should see "Proved the summary block works!" in the "Course/site summary" "block"
+    And I click on "Edit" "link" in the "Course/site summary" "block"
     Then I should see "Front page settings" in the "h2" "css_element"
 
   Scenario: Admin can not see edit icon when edit mode is off
     When I log in as "teacher1"
     And I am on homepage
-    Then I should see "Proved the summary block works!" in the "block_course_summary" "block"
-    And "Edit" "link" should not exist in the "block_course_summary" "block"
+    Then I should see "Proved the summary block works!" in the "Course/site summary" "block"
+    And "Edit" "link" should not exist in the "Course/site summary" "block"
diff --git a/blocks/glossary_random/tests/behat/glossary_random.feature b/blocks/glossary_random/tests/behat/glossary_random.feature
new file mode 100644 (file)
index 0000000..a3803a4
--- /dev/null
@@ -0,0 +1,111 @@
+@block @block_glossary_random
+Feature: Random glossary entry block is used in a course
+  In order to show the entries from glossary
+  As a teacher
+  I can add the random glossary entry to a course page
+
+  Background:
+    Given the following "courses" exist:
+      | fullname | shortname |
+      | Course 1 | C1        |
+    And the following "users" exist:
+      | username | firstname | lastname | email             |
+      | student1 | Sam1      | Student1 | student1@test.com |
+      | teacher1 | Terry1    | Teacher1 | teacher1@test.com |
+    And the following "course enrolments" exist:
+      | user     | course | role           |
+      | student1 | C1     | student        |
+      | teacher1 | C1     | editingteacher |
+
+  Scenario: Student can not see the block if it is not configured
+    When I log in as "teacher1"
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add the "Random glossary entry" block
+    Then I should see "Please configure this block using the edit icon" in the "block_glossary_random" "block"
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And "block_glossary_random" "block" should not exist
+    And I log out
+
+  Scenario: View random (last) entry in the glossary with auto approval
+    Given the following "activities" exist:
+      | activity | name         | intro                     | course | idnumber  | defaultapproval |
+      | glossary | GlossaryAuto | Test glossary description | C1     | glossary1 | 1               |
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add the "Random glossary entry" block
+    And I configure the "block_glossary_random" block
+    And I set the following fields to these values:
+      | Title                           | AutoGlossaryblock   |
+      | Take entries from this glossary | GlossaryAuto        |
+      | How a new entry is chosen       | Last modified entry |
+    And I press "Save changes"
+    And I log out
+    When I log in as "student1"
+    And I follow "Course 1"
+    Then I should see "There are no entries yet in the chosen glossary" in the "AutoGlossaryblock" "block"
+    And I click on "Add a new entry" "link" in the "AutoGlossaryblock" "block"
+    And I set the following fields to these values:
+      | Concept    | Concept1    |
+      | Definition | Definition1 |
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I should see "Concept1" in the "AutoGlossaryblock" "block"
+    And I should see "Definition1" in the "AutoGlossaryblock" "block"
+    And I should not see "There are no entries yet in the chosen glossary" in the "AutoGlossaryblock" "block"
+    And I click on "Add a new entry" "link" in the "AutoGlossaryblock" "block"
+    And I set the following fields to these values:
+      | Concept    | Concept2    |
+      | Definition | Definition2 |
+    And I press "Save changes"
+    And I follow "Course 1"
+    # Only the last entry appears in the block
+    And I should not see "Concept1" in the "AutoGlossaryblock" "block"
+    And I should not see "Definition1" in the "AutoGlossaryblock" "block"
+    And I should see "Concept2" in the "AutoGlossaryblock" "block"
+    And I should see "Definition2" in the "AutoGlossaryblock" "block"
+    And I click on "View all entries" "link" in the "AutoGlossaryblock" "block"
+    And I should see "GlossaryAuto" in the "#page-navbar" "css_element"
+    And I should see "Concept1" in the "#page-content" "css_element"
+    And I should see "Concept2" in the "#page-content" "css_element"
+    And I log out
+
+  Scenario: View random (last) entry in the glossary with manual approval
+    Given the following "activities" exist:
+      | activity | name           | intro                     | course | idnumber  | defaultapproval |
+      | glossary | GlossaryManual | Test glossary description | C1     | glossary2 | 0               |
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add the "Random glossary entry" block
+    And I configure the "block_glossary_random" block
+    And I set the following fields to these values:
+      | Title                           | ManualGlossaryblock |
+      | Take entries from this glossary | GlossaryManual      |
+      | How a new entry is chosen       | Last modified entry |
+    And I press "Save changes"
+    And I log out
+    When I log in as "student1"
+    And I follow "Course 1"
+    Then I should see "There are no entries yet in the chosen glossary" in the "ManualGlossaryblock" "block"
+    And I click on "Add a new entry" "link" in the "ManualGlossaryblock" "block"
+    And I set the following fields to these values:
+      | Concept    | Concept1    |
+      | Definition | Definition1 |
+    And I press "Save changes"
+    And I follow "Course 1"
+    And I should see "There are no entries yet in the chosen glossary" in the "ManualGlossaryblock" "block"
+    And I log out
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I should see "There are no entries yet in the chosen glossary" in the "ManualGlossaryblock" "block"
+    And I follow "GlossaryManual"
+    And I follow "Waiting approval"
+    And I follow "Approve"
+    And I click on "Course 1" "link" in the "#page-navbar" "css_element"
+    And I should see "Concept1" in the "ManualGlossaryblock" "block"
+    And I should see "Definition1" in the "ManualGlossaryblock" "block"
+    And I log out
diff --git a/blocks/glossary_random/tests/behat/glossary_random_frontpage.feature b/blocks/glossary_random/tests/behat/glossary_random_frontpage.feature
new file mode 100644 (file)
index 0000000..269f63b
--- /dev/null
@@ -0,0 +1,26 @@
+@block @block_glossary_random
+Feature: Random glossary entry block can be added to the frontpage
+  In order to show the entries from glossary on the frontpage
+  As a teacher
+  I can add the random glossary entry to the frontpage
+
+Scenario: Admin can add random glossary block to the frontpage
+  Given the following "activities" exist:
+    | activity   | name             | intro                          | course               | idnumber  |
+    | glossary   | Tips and Tricks  | Frontpage glossary description | Acceptance test site | glossary0 |
+  And I log in as "admin"
+  And I click on "Turn editing on" "link" in the "Administration" "block"
+  And I add the "Random glossary entry" block
+  And I configure the "block_glossary_random" block
+  And I set the following fields to these values:
+    | Title                           | Tip of the day  |
+    | Take entries from this glossary | Tips and Tricks |
+  And I press "Save changes"
+  And I click on "Add a new entry" "link" in the "Tip of the day" "block"
+  And I set the following fields to these values:
+    | Concept    | Never come late               |
+    | Definition | Come in time for your classes |
+  And I press "Save changes"
+  When I log out
+  Then I should see "Never come late" in the "Tip of the day" "block"
+  And I should see "Come in time for your classes" in the "Tip of the day" "block"
index cef37a7..c938df7 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * This file keeps track of upgrades to the html block
  *
- * @since 2.0
+ * @since Moodle 2.0
  * @package block_html
  * @copyright 2010 Dongsheng Cai
  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
diff --git a/blocks/html/tests/behat/configuring_html_block.feature b/blocks/html/tests/behat/configuring_html_block.feature
new file mode 100644 (file)
index 0000000..ad25530
--- /dev/null
@@ -0,0 +1,38 @@
+@block @block_html @core_block
+Feature: Adding and configuring HTML blocks
+  In order to have custom blocks on a page
+  As admin
+  I need to be able to create, configure and change HTML blocks
+
+  @javascript
+  Scenario: Configuring the HTML block with Javascript on
+    Given I log in as "admin"
+    When I click on "Turn editing on" "link" in the "Administration" "block"
+    And I add the "HTML" block
+    And I configure the "(new HTML block)" block
+    And I set the field "Content" to "Static text without a header"
+    And I press "Save changes"
+    Then I should not see "(new HTML block)"
+    And I configure the "block_html" block
+    And I set the field "Block title" to "The HTML block header"
+    And I set the field "Content" to "Static text with a header"
+    And I press "Save changes"
+    And "block_html" "block" should exist
+    And "The HTML block header" "block" should exist
+    And I should see "Static text with a header" in the "The HTML block header" "block"
+
+  Scenario: Configuring the HTML block with Javascript off
+    Given I log in as "admin"
+    When I click on "Turn editing on" "link" in the "Administration" "block"
+    And I add the "HTML" block
+    And I configure the "(new HTML block)" block
+    And I set the field "Content" to "Static text without a header"
+    And I press "Save changes"
+    Then I should not see "(new HTML block)"
+    And I configure the "block_html" block
+    And I set the field "Block title" to "The HTML block header"
+    And I set the field "Content" to "Static text with a header"
+    And I press "Save changes"
+    And "block_html" "block" should exist
+    And "The HTML block header" "block" should exist
+    And I should see "Static text with a header" in the "The HTML block header" "block"
diff --git a/blocks/html/tests/behat/course_block.feature b/blocks/html/tests/behat/course_block.feature
new file mode 100644 (file)
index 0000000..c44a758
--- /dev/null
@@ -0,0 +1,36 @@
+@block @block_html
+Feature: HTML blocks in a course
+  In order to have one or multiple HTML blocks in a course
+  As a teacher
+  I need to be able to create and change such blocks
+
+  Scenario: Adding HTML block in a course
+    Given the following "users" exist:
+      | username | firstname | lastname | email            |
+      | teacher1 | Terry1    | Teacher1 | teacher@asd.com  |
+      | student1 | Sam1      | Student1 | student1@asd.com |
+    And the following "courses" exist:
+      | fullname | shortname |
+      | Course 1 | C1        |
+    And the following "course enrolments" exist:
+      | user     | course | role           |
+      | teacher1 | C1     | editingteacher |
+      | student1 | C1     | student        |
+    When I log in as "teacher1"
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add the "HTML" block
+    And I configure the "(new HTML block)" block
+    And I set the field "Content" to "First block content"
+    And I set the field "Block title" to "First block header"
+    And I press "Save changes"
+    And I add the "HTML" block
+    And I configure the "(new HTML block)" block
+    And I set the field "Content" to "Second block content"
+    And I set the field "Block title" to "Second block header"
+    And I press "Save changes"
+    And I log out
+    And I log in as "student1"
+    And I follow "Course 1"
+    And I should see "First block content" in the "First block header" "block"
+    And I should see "Second block content" in the "Second block header" "block"
\ No newline at end of file
diff --git a/blocks/html/tests/behat/multiple_instances.feature b/blocks/html/tests/behat/multiple_instances.feature
new file mode 100644 (file)
index 0000000..45b608f
--- /dev/null
@@ -0,0 +1,41 @@
+@block @block_html
+Feature: Adding and configuring HTML blocks
+  In order to have one or multiple HTML blocks on a page
+  As admin
+  I need to be able to create, configure and change HTML blocks
+
+  Background:
+    Given I log in as "admin"
+    When I click on "Turn editing on" "link" in the "Administration" "block"
+    And I add the "HTML" block
+
+  Scenario: Other users can not see HTML block that has not been configured
+    Then "(new HTML block)" "block" should exist
+    And I log out
+    And "(new HTML block)" "block" should not exist
+    And "block_html" "block" should not exist
+
+  Scenario: Other users can see HTML block that has been configured even when it has no header
+    And I configure the "(new HTML block)" block
+    And I set the field "Content" to "Static text without a header"
+    And I press "Save changes"
+    Then I should not see "(new HTML block)"
+    And I log out
+    And I am on homepage
+    And "block_html" "block" should exist
+    And I should see "Static text without a header" in the "block_html" "block"
+    And I should not see "(new HTML block)"
+
+  Scenario: Adding multiple instances of HTML block on a page
+    And I configure the "block_html" block
+    And I set the field "Block title" to "The HTML block header"
+    And I set the field "Content" to "Static text with a header"
+    And I press "Save changes"
+    And I add the "HTML" block
+    And I configure the "(new HTML block)" block
+    And I set the field "Block title" to "The second HTML block header"
+    And I set the field "Content" to "Second block contents"
+    And I press "Save changes"
+    And I log out
+    Then I should see "Static text with a header" in the "The HTML block header" "block"
+    And I should see "Second block contents" in the "The second HTML block header" "block"
index f152729..17a2509 100644 (file)
@@ -18,7 +18,7 @@
  * This file contains classes used to manage the navigation structures in Moodle
  * and was introduced as part of the changes occuring in Moodle 2.0
  *
- * @since     2.0
+ * @since     Moodle 2.0
  * @package   block_navigation
  * @copyright 2009 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index a1a8367..a1497bf 100644 (file)
@@ -31,7 +31,7 @@
  * Please do not forget to use upgrade_set_timeout()
  * before any action that may take longer time to finish.
  *
- * @since 2.0
+ * @since Moodle 2.0
  * @package block_navigation
  * @copyright 2009 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 3134e59..9db482a 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * Form for editing global navigation instances.
  *
- * @since     2.0
+ * @since     Moodle 2.0
  * @package   block_navigation
  * @copyright 2009 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 432b0ed..0b8e6dc 100644 (file)
@@ -18,7 +18,7 @@
 /**
  * This file contains language strings used in the global navigation block
  *
- * @since 2.0
+ * @since Moodle 2.0
  * @package block_navigation
  * @copyright 2009 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 8387e08..c92ef41 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * Outputs the navigation tree.
  *
- * @since     2.0
+ * @since     Moodle 2.0
  * @package   block_navigation
  * @copyright 2009 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 7c953c9..4c8ad1b 100644 (file)
@@ -66,3 +66,36 @@ Feature: View my courses in navigation block
     And I expand "cat33" node
     And I should see "c331" in the "Navigation" "block"
     And I should not see "c332" in the "Navigation" "block"
+
+  @javascript
+  Scenario: I can expand categories and courses as guest
+    Given I set the following administration settings values:
+      | Show my course categories | 1 |
+      | Show all courses          | 1 |
+    And I log out
+    And I expand "Courses" node
+    And I should see "cat1" in the "Navigation" "block"
+    And I should see "cat2" in the "Navigation" "block"
+    And I should see "cat3" in the "Navigation" "block"
+    And I should not see "cat31" in the "Navigation" "block"
+    And I should not see "cat32" in the "Navigation" "block"
+    And I should not see "cat331" in the "Navigation" "block"
+    And I should not see "c1" in the "Navigation" "block"
+    And I should not see "c2" in the "Navigation" "block"
+    And I should not see "c31" in the "Navigation" "block"
+    And I should not see "c32" in the "Navigation" "block"
+    When I expand "cat3" node
+    And I expand "cat31" node
+    And I expand "cat1" node
+    And I should see "c1" in the "Navigation" "block"
+    And I expand "c1" node
+    Then I should see "cat1" in the "Navigation" "block"
+    And I should see "cat2" in the "Navigation" "block"
+    And I should see "cat3" in the "Navigation" "block"
+    And I should see "cat31" in the "Navigation" "block"
+    And I should see "cat32" in the "Navigation" "block"
+    And I should not see "cat331" in the "Navigation" "block"
+    And I should see "c1" in the "Navigation" "block"
+    And I should not see "c2" in the "Navigation" "block"
+    And I should see "c31" in the "Navigation" "block"
+    And I should not see "c32" in the "Navigation" "block"
index 42a472c..79f928d 100644 (file)
@@ -31,7 +31,7 @@
  * Please do not forget to use upgrade_set_timeout()
  * before any action that may take longer time to finish.
  *
- * @since 2.5
+ * @since Moodle 2.5
  * @package block_section_links
  * @copyright 2013 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 9fb281f..338855b 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * Renderer for the section links block.
  *
- * @since     2.5
+ * @since     Moodle 2.5
  * @package   block_section_links
  * @copyright 2013 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 2a98e9a..0b55523 100644 (file)
@@ -31,7 +31,7 @@
  * Please do not forget to use upgrade_set_timeout()
  * before any action that may take longer time to finish.
  *
- * @since 2.0
+ * @since Moodle 2.0
  * @package    block_selfcompletion
  * @copyright 2012 Mark Nelson <markn@moodle.com>
  * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 499dc85..14c486b 100644 (file)
@@ -18,7 +18,7 @@
  * This file contains classes used to manage the navigation structures in Moodle
  * and was introduced as part of the changes occuring in Moodle 2.0
  *
- * @since 2.0
+ * @since Moodle 2.0
  * @package block_settings
  * @copyright 2009 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 2e27da6..9406123 100644 (file)
@@ -31,7 +31,7 @@
  * Please do not forget to use upgrade_set_timeout()
  * before any action that may take longer time to finish.
  *
- * @since 2.0
+ * @since Moodle 2.0
  * @package block_settings
  * @copyright 2009 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 12683c7..0874ee6 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * Form for editing settings navigation instances.
  *
- * @since 2.0
+ * @since Moodle 2.0
  * @package block_settings
  * @copyright 2009 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 18c374b..f2ac617 100644 (file)
@@ -18,7 +18,7 @@
 /**
  * This file contains language strings used in the settings navigation block
  *
- * @since 2.0
+ * @since Moodle 2.0
  * @package block_settings
  * @copyright 2009 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 627ab00..a10250d 100644 (file)
@@ -83,13 +83,13 @@ class behat_blocks extends behat_base {
     public function i_open_the_blocks_action_menu($blockname) {
 
         if (!$this->running_javascript()) {
-            throw new DriverException('Blocks action menu not available when Javascript is disabled');
+            // Action menu does not need to be open if Javascript is off.
+            return;
         }
 
         // If it is already opened we do nothing.
-        $blocknode = $this->get_block_node($blockname);
-        $classes = array_flip(explode(' ', $blocknode->getAttribute('class')));
-        if (!empty($classes['action-menu-shown'])) {
+        $blocknode = $this->get_text_selector_node('block', $blockname);
+        if ($blocknode->hasClass('action-menu-shown')) {
             return;
         }
 
@@ -97,18 +97,18 @@ class behat_blocks extends behat_base {
     }
 
     /**
-     * Returns the DOM node of the block from <div>.
+     * Clicks on Configure block for specified block. Page must be in editing mode.
+     *
+     * Argument block_name may be either the name of the block or CSS class of the block.
      *
-     * @throws ElementNotFoundException Thrown by behat_base::find
-     * @param string $blockname The block name
-     * @return NodeElement
+     * @Given /^I configure the "(?P<block_name_string>(?:[^"]|\\")*)" block$/
+     * @param string $blockname
      */
-    protected function get_block_node($blockname) {
-
-        $blockname = $this->getSession()->getSelectorsHandler()->xpathLiteral($blockname);
-        $xpath = "//div[contains(concat(' ', normalize-space(@class), ' '), ' block ')][contains(., $blockname)]";
-
-        return $this->find('xpath', $xpath);
+    public function i_configure_the_block($blockname) {
+        // Note that since $blockname may be either block name or CSS class, we can not use the exact label of "Configure" link.
+        return array(
+            new Given('I open the "'.$this->escape($blockname).'" blocks action menu'),
+            new Given('I click on "Configure" "link" in the "'.$this->escape($blockname).'" "block"')
+        );
     }
-
 }
index c326c64..b51143a 100644 (file)
@@ -4,7 +4,6 @@ Feature: Add and configure blocks throughout the site
   As a manager
   I need to set and configure blocks throughout the site
 
-  @javascript
   Scenario: Add and configure a block throughtout the site
     Given the following "courses" exist:
       | fullname | shortname | category |
@@ -18,8 +17,7 @@ Feature: Add and configure blocks throughout the site
     And I log in as "manager1"
     And I follow "Turn editing on"
     And I add the "Comments" block
-    And I open the "Comments" blocks action menu
-    And I follow "Configure Comments block"
+    And I configure the "Comments" block
     And I set the following fields to these values:
       | Page contexts | Display throughout the entire site |
     And I press "Save changes"
@@ -27,8 +25,7 @@ Feature: Add and configure blocks throughout the site
     Then I should see "Comments" in the "Comments" "block"
     And I should see "Save comment" in the "Comments" "block"
     And I am on homepage
-    And I open the "Comments" blocks action menu
-    And I follow "Configure Comments block"
+    And I configure the "Comments" block
     And I set the following fields to these values:
       | Default weight | -10 (first) |
     And I press "Save changes"
index 7c496a8..179e77d 100644 (file)
@@ -35,19 +35,16 @@ Feature: Block appearances
     And I follow "Course 1"
     And I follow "Turn editing on"
     And I add the "Comments" block
-    And I open the "Comments" blocks action menu
-    And I follow "Configure Comments block"
+    And I configure the "Comments" block
     And I set the following fields to these values:
       | Display on page types | Any page |
     And I press "Save changes"
 
-  @javascript
   Scenario: Block settings can be modified so that a block apprears on any page
     When I follow "Test survey name"
     Then I should see "Comments" in the "Comments" "block"
     And I follow "Course 1"
-    And I open the "Comments" blocks action menu
-    And I follow "Configure Comments block"
+    And I configure the "Comments" block
     And I set the following fields to these values:
       | Display on page types | Any course page |
     And I press "Save changes"
@@ -55,11 +52,9 @@ Feature: Block appearances
     And I follow "Test survey name"
     And I should not see "Comments"
 
-  @javascript
   Scenario: Block settings can be modified so that a block can be hidden or moved
     When I follow "Test book name"
-    And I open the "Comments" blocks action menu
-    And I follow "Configure Comments block"
+    And I configure the "Comments" block
     And I set the following fields to these values:
       | Visible | No |
     And I press "Save changes"
@@ -68,8 +63,7 @@ Feature: Block appearances
     Then I should not see "Comments"
     And I expand "Course administration" node
     And I follow "Turn editing on"
-    And I open the "Comments" blocks action menu
-    And I follow "Configure Comments block"
+    And I configure the "Comments" block
     And I set the following fields to these values:
       | Visible | Yes |
       | Region  | Right |
index 1093de1..83ebacf 100644 (file)
@@ -15,7 +15,6 @@ Feature: Allowed blocks controls
       | user | course | role |
       | teacher1 | C1 | editingteacher |
 
-  @javascript
   Scenario: Blocks can be added with the default permissions
     Given I log in as "teacher1"
     And I follow "Course 1"
index 6981d33..7285d99 100644 (file)
@@ -4,7 +4,6 @@ Feature: The context of a block can always be returned to it's original state.
   As an admin
   I need to be able to return the block to original state
 
-  @javascript
   Scenario: Add and configure a block to display on every page and revert back
     Given the following "courses" exist:
       | fullname | shortname | category |
@@ -15,8 +14,7 @@ Feature: The context of a block can always be returned to it's original state.
     And I add the "Tags" block
     Then I should see "Tags" in the "Tags" "block"
     And I click on "Participants" "link" in the "//li[p/span[contains(normalize-space(string(.)), 'Current course')]]" "xpath_element"
-    And I open the "Tags" blocks action menu
-    And I follow "Configure Tags block"
+    And I configure the "Tags" block
     And I set the following fields to these values:
       | Display on page types | Any page |
     And I press "Save changes"
@@ -25,8 +23,7 @@ Feature: The context of a block can always be returned to it's original state.
       | Assignment name | Assignment1 |
       | Description | Description |
     And I follow "Assignment1"
-    And I open the "Tags" blocks action menu
-    And I follow "Configure Tags block"
+    And I configure the "Tags" block
     And I set the following fields to these values:
       | Display on page types | Any assignment module page |
     And I press "Save changes"
@@ -41,8 +38,7 @@ Feature: The context of a block can always be returned to it's original state.
       | Description | Description |
     And I follow "Assignment2"
     And I should see "Tags" in the "Tags" "block"
-    And I open the "Tags" blocks action menu
-    And I follow "Configure Tags block"
+    And I configure the "Tags" block
     And I set the following fields to these values:
       | Display on page types | Any page |
     And I press "Save changes"
index e6e341a..6b4f47b 100644 (file)
@@ -205,7 +205,7 @@ class cache_definition {
 
     /**
      * Gets set to true if this definition requires searchable stores.
-     * @since 2.4.4
+     * @since Moodle 2.4.4
      * @var bool
      */
     protected $requiresearchable = false;
@@ -734,7 +734,7 @@ class cache_definition {
 
     /**
      * Returns true if this definition requires a searchable cache.
-     * @since 2.4.4
+     * @since Moodle 2.4.4
      * @return bool
      */
     public function require_searchable() {
index d7dad36..825a441 100644 (file)
@@ -309,7 +309,7 @@ class cache_factory {
 
     /**
      * Returns the cache instances that have been used within this request.
-     * @since 2.6
+     * @since Moodle 2.6
      * @return array
      */
     public function get_caches_in_use() {
index 39ee2e4..02bd243 100644 (file)
@@ -719,7 +719,8 @@ class cache_helper {
             return $stores;
         } else {
             $stores = self::get_cache_stores($definition);
-            if (count($stores) === 0) {
+            // If mappingsonly is set, having 0 stores is ok.
+            if ((count($stores) === 0) && (!$definition->is_for_mappings_only())) {
                 // No suitable stores we found for the definition. We need to come up with a sensible default.
                 // If this has happened we can be sure that the user has mapped custom stores to either the
                 // mode of the definition. The first alternative to try is the system default for the mode.
index 24996ed..28bcf15 100644 (file)
@@ -344,7 +344,7 @@ interface cache_is_key_aware {
  * Cache stores can choose to implement this interface.
  * In order for a store to be usable as a session cache it must implement this interface.
  *
- * @since 2.4.4
+ * @since Moodle 2.4.4
  */
 interface cache_is_searchable {
     /**
index c59af74..ae2ba70 100644 (file)
@@ -892,7 +892,7 @@ class cache implements cache_loader {
     /**
      * Returns the loader associated with this instance.
      *
-     * @since 2.4.4
+     * @since Moodle 2.4.4
      * @return cache|false
      */
     protected function get_loader() {
@@ -902,7 +902,7 @@ class cache implements cache_loader {
     /**
      * Returns the data source associated with this cache.
      *
-     * @since 2.4.4
+     * @since Moodle 2.4.4
      * @return cache_data_source|false
      */
     protected function get_datasource() {
index aad5043..ab22575 100644 (file)
@@ -87,7 +87,7 @@ interface cache_store_interface {
  * All cache store plugins must extend this base class.
  * It lays down the foundation for what is required of a cache store plugin.
  *
- * @since 2.4
+ * @since Moodle 2.4
  * @package    core
  * @category   cache
  * @copyright  2012 Sam Hemelryk
@@ -256,7 +256,7 @@ abstract class cache_store implements cache_store_interface {
     /**
      * Performs any necessary operation when the store instance has been created.
      *
-     * @since 2.5
+     * @since Moodle 2.5
      */
     public function instance_created() {
         // By default, do nothing.
@@ -267,7 +267,7 @@ abstract class cache_store implements cache_store_interface {
      *
      * This method may be called before the store has been initialised.
      *
-     * @since 2.5
+     * @since Moodle 2.5
      * @see cleanup()
      */
     public function instance_deleted() {
index 2267afa..5a85f14 100644 (file)
@@ -470,6 +470,33 @@ class core_cache_testcase extends advanced_testcase {
         $this->assertEquals('Test has no value really.', $cache->get('Test'));
     }
 
+    /**
+     * Test the mappingsonly setting.
+     */
+    public function test_definition_mappings_only() {
+        $instance = cache_config_phpunittest::instance(true);
+        $instance->phpunit_add_definition('phpunit/mappingsonly', array(
+            'mode' => cache_store::MODE_APPLICATION,
+            'component' => 'phpunit',
+            'area' => 'mappingsonly',
+            'mappingsonly' => true
+        ));
+        $instance->phpunit_add_definition('phpunit/nonmappingsonly', array(
+            'mode' => cache_store::MODE_APPLICATION,
+            'component' => 'phpunit',
+            'area' => 'nonmappingsonly',
+            'mappingsonly' => false
+        ));
+
+        $cacheonly = cache::make('phpunit', 'mappingsonly');
+        $this->assertInstanceOf('cache_application', $cacheonly);
+        $this->assertEquals('cachestore_dummy', $cacheonly->phpunit_get_store_class());
+
+        $cachenon = cache::make('phpunit', 'nonmappingsonly');
+        $this->assertInstanceOf('cache_application', $cachenon);
+        $this->assertEquals('cachestore_file', $cachenon->phpunit_get_store_class());
+    }
+
     /**
      * Test a very basic definition.
      */
index 443382f..9df577b 100644 (file)
@@ -526,9 +526,9 @@ class comment {
             $c->content     = $u->ccontent;
             $c->format      = $u->cformat;
             $c->timecreated = $u->ctimecreated;
-            $c->strftimeformat = get_string('strftimerecent', 'langconfig');
+            $c->strftimeformat = get_string('strftimerecentfull', 'langconfig');
             $url = new moodle_url('/user/view.php', array('id'=>$u->id, 'course'=>$this->courseid));
-            $c->profileurl = $url->out(true);
+            $c->profileurl = $url->out(false); // URL should not be escaped just yet.
             $c->fullname = fullname($u);
             $c->time = userdate($c->timecreated, $c->strftimeformat);
             $c->content = format_text($c->content, $c->format, $formatoptions);
index af2a6c6..b51d77d 100644 (file)
@@ -269,7 +269,7 @@ abstract class format_base {
      * So if 'Return to course' does not make sense in your format your should probably return false.
      *
      * @return boolean
-     * @since 2.6
+     * @since Moodle 2.6
      */
     public function has_view_page() {
         return true;
index 3c84a15..a9c6223 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * This file contains main class for the course format Social
  *
- * @since     2.0
+ * @since     Moodle 2.0
  * @package   format_social
  * @copyright 2009 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 7c1ee6e..aa04378 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * This file contains main class for the course format Topic
  *
- * @since     2.0
+ * @since     Moodle 2.0
  * @package   format_topics
  * @copyright 2009 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index e361def..f554d9c 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * This file contains main class for the course format Weeks
  *
- * @since     2.0
+ * @since     Moodle 2.0
  * @package   format_weeks
  * @copyright 2009 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 42dd374..6c13a7d 100644 (file)
@@ -1645,7 +1645,7 @@ function set_coursemodule_visible($id, $visible) {
  * event to the DB.
  *
  * @param int $cmid the course module id
- * @since 2.5
+ * @since Moodle 2.5
  */
 function course_delete_module($cmid) {
     global $CFG, $DB;
index b5037df..da6e13b 100644 (file)
@@ -18,7 +18,7 @@
 /**
  * This file contains functions used by course reports
  *
- * @since 2.1
+ * @since Moodle 2.1
  * @package coursereport
  * @copyright 2011 Andrew Davis
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 533537a..a682c37 100644 (file)
@@ -23,7 +23,7 @@
  * The reason that we created this file was so that user didn't get redirected back
  * to the course view page only to be redirected again.
  *
- * @since 2.0
+ * @since Moodle 2.0
  * @package course
  * @copyright 2009 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index cf86d89..a306319 100644 (file)
@@ -122,9 +122,7 @@ class behat_course extends behat_base {
     public function i_go_to_the_courses_management_page() {
         return array(
             new Given('I am on homepage'),
-            new Given('I expand "' . get_string('administrationsite') . '" node'),
-            new Given('I expand "' . get_string('courses', 'admin') . '" node'),
-            new Given('I follow "' . get_string('coursemgmt', 'admin') . '"')
+            new Given('I navigate to "' . get_string('coursemgmt', 'admin') . '" node in "' . get_string('administrationsite') . ' > ' . get_string('courses', 'admin') . '"')
         );
     }
 
index c881ecd..d3e7e55 100644 (file)
@@ -12,9 +12,7 @@ Feature: The maximum number of weeks/topics in a course can be configured
       | user | course | role |
       | manager1 | Acceptance test site | manager |
     And I log in as "admin"
-    And I expand "Site administration" node
-    And I expand "Courses" node
-    And I follow "Course default settings"
+    And I navigate to "Course default settings" node in "Site administration >  Courses"
 
   @javascript
   Scenario: The number of sections can be increased and the limits are applied to courses
index 01ad3ab..473a757 100644 (file)
@@ -20,7 +20,7 @@
  * If we rewrite MNet as proposed in MDL-21993 this file would contain
  * just a declaration of xml-rpc methods that this plugin publishes.
  *
- * @since      2.0
+ * @since      Moodle 2.0
  * @package    enrol_mnet
  * @copyright  2010 Penny Leach
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 43ba596..b45dc24 100644 (file)
@@ -251,9 +251,9 @@ function grade_get_grade_items_for_activity($cm, $only_main_item=false) {
 
     if (!isset($cm->modname)) {
         $params = array($cm->id);
-        $cm = $DB->get_record_sql("SELECT cm.*, m.name, md.name as modname
+        $cm = $DB->get_record_sql("SELECT cm.*, md.name as modname
                                     FROM {course_modules} cm,
-                                         {modules} md,
+                                         {modules} md
                                    WHERE cm.id = ? AND md.id = cm.module", $params);
     }
 
index dca1a9e..c284123 100644 (file)
@@ -50,4 +50,15 @@ class core_grade_querylib_testcase extends advanced_testcase {
         $this->assertEquals(1, count($cms));
         $this->assertTrue(isset($cms[$forum1->cmid]));
     }
+
+    public function test_grade_get_grade_items_for_activity() {
+        $this->resetAfterTest(true);
+
+        $course = $this->getDataGenerator()->create_course();
+        $forum = $this->getDataGenerator()->create_module('forum', array('course'=>$course->id));
+        $cm = get_coursemodule_from_id('forum', $forum->cmid, $forum->course);
+        unset($cm->modname);
+        $grade = grade_get_grade_items_for_activity($cm);
+
+    }
 }
index c31ade1..c62c390 100644 (file)
@@ -135,7 +135,7 @@ class autogroup_form extends moodleform {
         $mform->setType('seed', PARAM_INT);
 
         $buttonarray = array();
-        $buttonarray[] = &$mform->createElement('submit', 'preview', get_string('preview'), 'xx');
+        $buttonarray[] = &$mform->createElement('submit', 'preview', get_string('preview'));
         $buttonarray[] = &$mform->createElement('submit', 'submitbutton', get_string('submit'));
         $buttonarray[] = &$mform->createElement('cancel');
         $mform->addGroup($buttonarray, 'buttonar', '', array(' '), false);
index 7108b6a..2d61e4a 100644 (file)
@@ -34,8 +34,8 @@ $string['admindirname'] = 'Admin-Verzeichnis';
 $string['availablelangs'] = 'Verfügbare Sprachpakete';
 $string['chooselanguagehead'] = 'Sprache wählen';
 $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.';
-$string['clialreadyconfigured'] = 'Die Datei config.php existiert bereits. Bitte benutzen Sie admin/cli/install_database.php, wenn sie diese Website installieren möchten.';
-$string['clialreadyinstalled'] = 'Die Datei config.php existiert bereits. Bitte benutzen Sie admin/cli/upgrade.php, wenn Sie diese Website aktualisieren möchten.';
+$string['clialreadyconfigured'] = 'Die Datei config.php existiert bereits. Bitte benutzen Sie admin/cli/install_database.php, wenn Sie diese Site installieren möchten.';
+$string['clialreadyinstalled'] = 'Die Datei config.php existiert bereits. Bitte benutzen Sie admin/cli/install_database.php, wenn Sie diese Site aktualisieren möchten.';
 $string['cliinstallheader'] = 'Installation von Moodle {$a} über die Kommandozeile';
 $string['databasehost'] = 'Datenbank-Server';
 $string['databasename'] = 'Datenbank-Name';
@@ -64,11 +64,11 @@ $string['pathshead'] = 'Pfade bestätigen';
 $string['pathsrodataroot'] = 'Das Verzeichnis dataroot ist schreibgeschützt.';
 $string['pathsroparentdataroot'] = 'Das Verzeichnis ({$a->parent}) ist schreibgeschützt. Deswegen kann das Datenverzeichnis ({$a->dataroot})  vom Installer nicht angelegt werden.';
 $string['pathssubadmindir'] = 'Einige Webserver benutzen /admin als speziellen Link, um auf Einstellungsseiten oder Ähnliches zu verweisen. Unglücklicherweise kollidiert dies mit dem standardmäßigen Verzeichnis für die Moodle-Administration. Sie können dieses Problem beheben, indem Sie das Verzeichnis admin in Ihrer Moodle-Installation umbenennen und den neuen Namen hier eingeben (z.B. <em>moodleadmin</em>). Mit dieser Änderung werden alle Admin-Links korrigiert.';
-$string['pathssubdataroot'] = 'Sie benötigen einen Platz, wo Moodle hochgeladene Dateien abspeichern kann. Dieses Verzeichnis muss Lese- und Schreibrechte für das Nutzerkonto besitzen, mit dem Ihr Webservers läuft (üblicherweise \'nobody\', \'apache\' oder \'www\'). Außerdem sollte das Verzeichnis nicht direkt aus dem Internet erreichbar sein. Das Intallationsskript wird versuchen, ein solches Verzeichnis zu erstellen, falls es nicht existiert.</p>';
-$string['pathssubdirroot'] = 'Vollständiger Pfad der Moodle-Installation';
-$string['pathssubwwwroot'] = 'Vollständige Webadresse für den Zugriff auf Moodle. Es ist nicht möglich, über unterschiedliche Adressen auf Moodle zuzugreifen. Sollte Ihre Website mehrere öffentliche Adressen verwenden, so müssen Sie eine Adresse festlegen und für die übrigen Adressen dauerhafte Weiterleitungen dorthin einrichten.
-<p>Falls Ihre Website gleichzeitig im Intranet und im Internet erreichbar ist, so tragen Sie die öffentliche Adresse ein. Konfigurieren Sie den DNS so, dass Moodle auch aus dem Intranet über die öffentliche Adresse erreichbar ist.
-<p>Führen Sie Ihre Moodle-Installation unbedingt mit der richtigen Adresse durch, weil es andernfalls zu Problemen kommen könnte.';
+$string['pathssubdataroot'] = '<p>Sie benötigen einen Platz, wo Moodle hochgeladene Dateien abspeichern kann. </p><p>Dieses Verzeichnis muss Lese- und Schreibrechte für das Nutzerkonto besitzen, mit dem Ihr Webservers läuft (üblicherweise \'nobody\', \'apache\' oder \'www-data).</p><p>  Außerdem sollte das Verzeichnis nicht direkt aus dem Internet erreichbar sein. </p><p>Das Intallationsskript wird versuchen, ein solches Verzeichnis zu erstellen, falls es nicht existiert.</p>';
+$string['pathssubdirroot'] = '<p>Vollständiger Pfad der Moodle-Installation.</p>';
+$string['pathssubwwwroot'] = '<p>Webadresse, die ein Nutzer im Browser eingibt, um auf Moodle zuzugreifen.</p><p> Es ist nicht möglich, über unterschiedliche Adressen auf Moodle zuzugreifen. Sollte Ihre Website mehrere öffentliche Adressen verwenden, so müssen Sie eine Adresse festlegen und für die übrigen Adressen dauerhafte Weiterleitungen dorthin einrichten.</p>
+<p>Falls Ihre Website gleichzeitig im Intranet und im Internet erreichbar ist, so tragen Sie die öffentliche Adresse ein. Konfigurieren Sie den DNS so, dass Moodle auch aus dem Intranet über die öffentliche Adresse erreichbar ist.</p>
+<p>Führen Sie Ihre Moodle-Installation unbedingt mit der richtigen Adresse durch, weil es andernfalls zu Problemen kommen könnte.</p>';
 $string['pathsunsecuredataroot'] = 'Der Speicherort des Verzeichnisses \'dataroot\' ist unsicher';
 $string['pathswrongadmindir'] = 'Das Admin-Verzeichnis existiert nicht';
 $string['phpextension'] = 'PHP-Extension {$a}';
diff --git a/install/lang/oc_lnc/langconfig.php b/install/lang/oc_lnc/langconfig.php
new file mode 100644 (file)
index 0000000..ffb2767
--- /dev/null
@@ -0,0 +1,34 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['parentlanguage'] = 'fr';
+$string['thislanguage'] = 'Lengadocian';
diff --git a/install/lang/oc_lnc/moodle.php b/install/lang/oc_lnc/moodle.php
new file mode 100644 (file)
index 0000000..cba51e1
--- /dev/null
@@ -0,0 +1,36 @@
+<?php
+
+// This file is part of Moodle - http://moodle.org/
+//
+// Moodle is free software: you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation, either version 3 of the License, or
+// (at your option) any later version.
+//
+// Moodle is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
+
+/**
+ * Automatically generated strings for Moodle installer
+ *
+ * Do not edit this file manually! It contains just a subset of strings
+ * needed during the very first steps of installation. This file was
+ * generated automatically by export-installer.php (which is part of AMOS
+ * {@link http://docs.moodle.org/dev/Languages/AMOS}) using the
+ * list of strings defined in /install/stringnames.txt.
+ *
+ * @package   installer
+ * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+$string['language'] = 'Langue';
+$string['next'] = 'Seguent';
+$string['previous'] = 'Précédent';
+$string['reload'] = 'Actualiser';
index d146236..9951d3f 100644 (file)
@@ -34,6 +34,7 @@ $string['hidden_marker'] = '(hidden otherwise)';
 $string['hidden_individual'] = 'Hidden entirely if user does not meet this condition';
 $string['invalid'] = 'Please set';
 $string['itemheading'] = '{$a->number} {$a->type} restriction';
+$string['item_unknowntype'] = 'These restrictions use a plugin which is no longer available (if it is okay to remove that restriction, delete it below)';
 $string['shown_individual'] = 'Displayed greyed-out if user does not meet this condition';
 $string['hide_verb'] = 'Click to hide';
 $string['show_verb'] = 'Click to show';
index 2ba5123..a843c19 100644 (file)
@@ -146,6 +146,7 @@ $string['answer'] = 'Answer';
 $string['any'] = 'Any';
 $string['approve'] = 'Approve';
 $string['appearance'] = 'Appearance';
+$string['areyousure'] = 'Are you sure?';
 $string['areyousuretorestorethis'] = 'Do you want to continue?';
 $string['areyousuretorestorethisinfo'] = 'Later in this process you will have a choice of adding this backup to an existing course or creating a completely new course.';
 $string['asc'] = 'Ascending';
@@ -255,6 +256,7 @@ $string['clickhere'] = 'Click here ...';
 $string['clicktohideshow'] = 'Click to expand or collapse';
 $string['clicktochangeinbrackets'] = '{$a} (Click to change)';
 $string['closewindow'] = 'Close this window';
+$string['closebuttontitle'] = 'Close';
 $string['collapse'] = 'Collapse';
 $string['collapseall'] = 'Collapse all';
 $string['collapsecategory'] = 'Collapse {$a}';
@@ -1849,6 +1851,7 @@ $string['turneditingon'] = 'Turn editing on';
 $string['undecided'] = 'Undecided';
 $string['unfinished'] = 'Unfinished';
 $string['unknowncategory'] = 'Unknown category';
+$string['unknownerror'] = 'Unknown error';
 $string['unlimited'] = 'Unlimited';
 $string['unpacking'] = 'Unpacking {$a}';
 $string['unsafepassword'] = 'Unsafe password - try something else';
index 7d316c4..147da15 100644 (file)
@@ -1269,7 +1269,7 @@ function reload_all_capabilities() {
  * Useful for the "temporary guest" access we grant to logged-in users.
  * This is useful for enrol plugins only.
  *
- * @since 2.2
+ * @since Moodle 2.2
  * @param context_course $coursecontext
  * @param int $roleid
  * @return void
@@ -1309,7 +1309,7 @@ function load_temp_course_role(context_course $coursecontext, $roleid) {
  * Removes any extra guest roles from current USER->access array.
  * This is useful for enrol plugins only.
  *
- * @since 2.2
+ * @since Moodle 2.2
  * @param context_course $coursecontext
  * @return void
  */
@@ -4975,7 +4975,7 @@ function role_change_permission($roleid, $context, $capname, $permission) {
  * @category  access
  * @copyright Petr Skoda {@link http://skodak.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @since     2.2
+ * @since     Moodle 2.2
  *
  * @property-read int $id context id
  * @property-read int $contextlevel CONTEXT_SYSTEM, CONTEXT_COURSE, etc.
@@ -5786,7 +5786,7 @@ abstract class context extends stdClass implements IteratorAggregate {
  * @category  access
  * @copyright Petr Skoda {@link http://skodak.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @since     2.2
+ * @since     Moodle 2.2
  */
 class context_helper extends context {
 
@@ -6062,7 +6062,7 @@ class context_helper extends context {
  * @category  access
  * @copyright Petr Skoda {@link http://skodak.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @since     2.2
+ * @since     Moodle 2.2
  */
 class context_system extends context {
     /**
@@ -6303,7 +6303,7 @@ class context_system extends context {
  * @category  access
  * @copyright Petr Skoda {@link http://skodak.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @since     2.2
+ * @since     Moodle 2.2
  */
 class context_user extends context {
     /**
@@ -6487,7 +6487,7 @@ class context_user extends context {
  * @category  access
  * @copyright Petr Skoda {@link http://skodak.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @since     2.2
+ * @since     Moodle 2.2
  */
 class context_coursecat extends context {
     /**
@@ -6716,7 +6716,7 @@ class context_coursecat extends context {
  * @category  access
  * @copyright Petr Skoda {@link http://skodak.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @since     2.2
+ * @since     Moodle 2.2
  */
 class context_course extends context {
     /**
@@ -6935,7 +6935,7 @@ class context_course extends context {
  * @category  access
  * @copyright Petr Skoda {@link http://skodak.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @since     2.2
+ * @since     Moodle 2.2
  */
 class context_module extends context {
     /**
@@ -7174,7 +7174,7 @@ class context_module extends context {
  * @category  access
  * @copyright Petr Skoda {@link http://skodak.org}
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @since     2.2
+ * @since     Moodle 2.2
  */
 class context_block extends context {
     /**
index 457f8d9..e2e319a 100644 (file)
@@ -19,7 +19,7 @@
  * This file is used to deliver a branch from the navigation structure
  * in XML format back to a page from an AJAX call
  *
- * @since 2.0
+ * @since Moodle 2.0
  * @package core
  * @copyright 2009 Sam Hemelryk
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 459d1c3..18a8d7f 100644 (file)
@@ -19,7 +19,7 @@
  * This file is used to deliver a branch from the site administration
  * in XML format back to a page from an AJAX call
  *
- * @since 2.6
+ * @since Moodle 2.6
  * @package core
  * @copyright 2013 Rajesh Taneja <rajesh@moodle.com>
  * @license   http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 92ac007..2be318e 100644 (file)
@@ -518,7 +518,7 @@ class auth_plugin_base {
      * authentication method manually is allowed.
      *
      * @return bool
-     * @since 2.6
+     * @since Moodle 2.6
      */
     function can_be_manually_set() {
         // Override if needed.
index ddacab4..85dde95 100644 (file)
@@ -96,7 +96,10 @@ XPATH
     normalize-space(descendant::div[@class='hd']) = %locator%]
 XPATH
         , 'block' => <<<XPATH
-//div[contains(concat(' ', normalize-space(@class), ' '), concat(' ', %locator%, ' '))] | //div[contains(concat(' ', normalize-space(@class), ' '), ' block ')]/descendant::h2[normalize-space(.) = %locator%]/ancestor::div[contains(concat(' ', normalize-space(@class), ' '), ' block ')]
+//div[contains(concat(' ', normalize-space(@class), ' '), ' block ') and
+    (contains(concat(' ', normalize-space(@class), ' '), concat(' ', %locator%, ' ')) or
+     descendant::h2[normalize-space(.) = %locator%] or
+     @aria-label = %locator%)]
 XPATH
         , 'region' => <<<XPATH
 //*[self::div | self::section | self::aside | self::header | self::footer][./@id = %locator%]
@@ -105,7 +108,8 @@ XPATH
 .//tr[contains(normalize-space(.), %locator%)]
 XPATH
         , 'filemanager' => <<<XPATH
-//div[contains(concat(' ', normalize-space(@class), ' '), ' ffilemanager ')]/descendant::input[@id = //label[contains(normalize-space(string(.)), %locator%)]/@for]
+//div[contains(concat(' ', normalize-space(@class), ' '), ' ffilemanager ')]
+    /descendant::input[@id = //label[contains(normalize-space(string(.)), %locator%)]/@for]
 XPATH
     );
 
index 4f46422..d5eab52 100644 (file)
@@ -75,7 +75,7 @@ class message_viewed extends base {
      * @return string
      */
     public function get_description() {
-        return "The user with id '$this->relateduserid' read a message from the user with id '$this->userid'.";
+        return "The user with id '$this->userid' read a message from the user with id '$this->relateduserid'.";
     }
 
     /**
index 3ea29bb..7f84fbc 100644 (file)
@@ -65,8 +65,8 @@ class user_enrolment_created extends base {
      * @return string
      */
     public function get_description() {
-        return "The user with id '$this->userid' enrolled the user with id '$this->relateduserid' in the course with " .
-            "id '$this->courseid'.";
+        return "The user with id '$this->userid' enrolled the user with id '$this->relateduserid' using the enrolment method " .
+            "'{$this->other['enrol']}' in the course with id '$this->courseid'.";
     }
 
     /**
index 12eb878..de88628 100644 (file)
@@ -69,7 +69,7 @@ class user_profile_viewed extends base {
      */
     public function get_description() {
         return "The user with id '$this->userid' viewed the profile for the user with id '$this->relateduserid' in the course " .
-            "with id '{$this->other['courseid']}'.";
+            "with id '$this->courseid'.";
     }
 
     /**
@@ -78,7 +78,7 @@ class user_profile_viewed extends base {
      * @return \moodle_url
      */
     public function get_url() {
-        return new \moodle_url('/user/view.php', array('id' => $this->relateduserid, 'course' => $this->other['courseid']));
+        return new \moodle_url('/user/view.php', array('id' => $this->relateduserid, 'course' => $this->courseid));
     }
 
     /**
@@ -87,7 +87,7 @@ class user_profile_viewed extends base {
      * @return array
      */
     protected function get_legacy_logdata() {
-        return array($this->other['courseid'], 'user', 'view', 'view.php?id=' . $this->relateduserid . '&course=' .
-            $this->other['courseid'], $this->relateduserid);
+        return array($this->courseid, 'user', 'view', 'view.php?id=' . $this->relateduserid . '&course=' .
+            $this->courseid, $this->relateduserid);
     }
 }
index 10ccbf4..1444eff 100644 (file)
@@ -53,4 +53,13 @@ class availability extends base {
 
         return $enabled;
     }
+
+    /**
+     * Defines if there should be a way to uninstall the plugin via the administration UI.
+     *
+     * @return bool
+     */
+    public function is_uninstall_allowed() {
+        return true;
+    }
 }
index 22c5076..d5c3939 100644 (file)
@@ -52,7 +52,7 @@ class delete_unconfirmed_users_task extends scheduled_task {
             $rs = $DB->get_recordset_sql ("SELECT *
                                              FROM {user}
                                             WHERE confirmed = 0 AND firstaccess > 0
-                                                  AND firstaccess < ?", array($cuttime));
+                                                  AND firstaccess < ? AND deleted = 0", array($cuttime));
             foreach ($rs as $user) {
                 delete_user($user); // We MUST delete user properly first.
                 $DB->delete_records('user', array('id' => $user->id)); // This is a bloody hack, but it might work.
index 5867ce0..01a7fbf 100644 (file)
@@ -60,8 +60,11 @@ class file_temp_cleanup_task extends scheduled_task {
             // Check if file or directory is older than the given time.
             if ($iter->getMTime() < $time) {
                 if ($iter->isDir() && !$iter->isDot()) {
-                    if (@rmdir($node) === false) {
-                        mtrace("Failed removing directory '$node'.");
+                    // Don't attempt to delete the directory if it isn't empty.
+                    if (!glob($node. DIRECTORY_SEPARATOR . '*')) {
+                        if (@rmdir($node) === false) {
+                            mtrace("Failed removing directory '$node'.");
+                        }
                     }
                 }
                 if ($iter->isFile()) {
index 7b13d75..0cba907 100644 (file)
@@ -256,7 +256,7 @@ class core_text {
      * @param string $needle The string to find in haystack.
      * @param boolean $part If true, returns the portion before needle, else return the portion after (including needle).
      * @return string|false False when not found.
-     * @since 2.4.6, 2.5.2, 2.6
+     * @since Moodle 2.4.6, 2.5.2, 2.6
      */
     public static function strrchr($haystack, $needle, $part = false) {
 
index 06612bb..2bd94d6 100644 (file)
@@ -176,9 +176,9 @@ function css_chunk_by_selector_count($css, $importurl, $maxselectors = 4095, $bu
             }
         }
 
-        // Let's count the number of selectors, but only if we are not in a rule as they
-        // can contain commas too.
-        if (!$inrule && $char === ',') {
+        // Let's count the number of selectors, but only if we are not in a rule, or in
+        // the definition of a media query, as they can contain commas too.
+        if (!$mediacoming && !$inrule && $char === ',') {
             $selectorcount++;
         }
 
@@ -195,6 +195,12 @@ function css_chunk_by_selector_count($css, $importurl, $maxselectors = 4095, $bu
                 }
             } else {
                 $inrule--;
+                // Handle stupid broken CSS where there are too many } brackets,
+                // as this can cause it to break (with chunking) where it would
+                // coincidentally have worked otherwise.
+                if ($inrule < 0) {
+                    $inrule = 0;
+                }
             }
 
             // We are not in a media query, and there is no pending rule, it is safe to split here.
index efb96fa..c3111c1 100644 (file)
@@ -3628,5 +3628,34 @@ function xmldb_main_upgrade($oldversion) {
         upgrade_main_savepoint(true, 2014050100.00);
     }
 
+    // MDL-32543 Make sure that the log table has correct length for action and url fields.
+    if ($oldversion < 2014051200.02) {
+
+        $table = new xmldb_table('log');
+
+        $columns = $DB->get_columns('log');
+        if ($columns['action']->max_length < 40) {
+            $index1 = new xmldb_index('course-module-action', XMLDB_INDEX_NOTUNIQUE, array('course', 'module', 'action'));
+            if ($dbman->index_exists($table, $index1)) {
+                $dbman->drop_index($table, $index1);
+            }
+            $index2 = new xmldb_index('action', XMLDB_INDEX_NOTUNIQUE, array('action'));
+            if ($dbman->index_exists($table, $index2)) {
+                $dbman->drop_index($table, $index2);
+            }
+            $field = new xmldb_field('action', XMLDB_TYPE_CHAR, '40', null, XMLDB_NOTNULL, null, null, 'cmid');
+            $dbman->change_field_precision($table, $field);
+            $dbman->add_index($table, $index1);
+            $dbman->add_index($table, $index2);
+        }
+
+        if ($columns['url']->max_length < 100) {
+            $field = new xmldb_field('url', XMLDB_TYPE_CHAR, '100', null, XMLDB_NOTNULL, null, null, 'action');
+            $dbman->change_field_precision($table, $field);
+        }
+
+        upgrade_main_savepoint(true, 2014051200.02);
+    }
+
     return true;
 }
index d53a172..264afcf 100644 (file)
@@ -1617,7 +1617,7 @@ abstract class moodle_database {
      * This method is intended for inserting of large number of small objects,
      * do not use for huge objects with text or binary fields.
      *
-     * @since 2.7
+     * @since Moodle 2.7
      *
      * @param string $table  The database table to be inserted into
      * @param array|Traversable $dataobjects list of objects to be inserted, must be compatible with foreach
@@ -2229,7 +2229,7 @@ abstract class moodle_database {
     /**
      * Does this driver support tool_replace?
      *
-     * @since 2.6.1
+     * @since Moodle 2.6.1
      * @return bool
      */
     public function replace_all_text_supported() {
@@ -2239,7 +2239,7 @@ abstract class moodle_database {
     /**
      * Replace given text in all rows of column.
      *
-     * @since 2.6.1
+     * @since Moodle 2.6.1
      * @param string $table name of the table
      * @param database_column_info $column
      * @param string $search
index 1360898..0b343f0 100644 (file)
@@ -1266,7 +1266,7 @@ s only returning name of SQL substring function, it now requires all parameters.
     /**
      * Does this driver support tool_replace?
      *
-     * @since 2.6.1
+     * @since Moodle 2.6.1
      * @return bool
      */
     public function replace_all_text_supported() {
index c3c2769..5ec79cc 100644 (file)
@@ -1153,7 +1153,7 @@ class mysqli_native_moodle_database extends moodle_database {
      * This method is intended for inserting of large number of small objects,
      * do not use for huge objects with text or binary fields.
      *
-     * @since 2.7
+     * @since Moodle 2.7
      *
      * @param string $table  The database table to be inserted into
      * @param array|Traversable $dataobjects list of objects to be inserted, must be compatible with foreach
@@ -1535,7 +1535,7 @@ class mysqli_native_moodle_database extends moodle_database {
     /**
      * Does this driver support tool_replace?
      *
-     * @since 2.6.1
+     * @since Moodle 2.6.1
      * @return bool
      */
     public function replace_all_text_supported() {
index 1b8150c..e369d39 100644 (file)
@@ -950,7 +950,7 @@ class pgsql_native_moodle_database extends moodle_database {
      * This method is intended for inserting of large number of small objects,
      * do not use for huge objects with text or binary fields.
      *
-     * @since 2.7
+     * @since Moodle 2.7
      *
      * @param string $table  The database table to be inserted into
      * @param array|Traversable $dataobjects list of objects to be inserted, must be compatible with foreach
@@ -1345,7 +1345,7 @@ class pgsql_native_moodle_database extends moodle_database {
     /**
      * Does this driver support tool_replace?
      *
-     * @since 2.6.1
+     * @since Moodle 2.6.1
      * @return bool
      */
     public function replace_all_text_supported() {
index e13047e..a2232ab 100644 (file)
@@ -1333,7 +1333,7 @@ class sqlsrv_native_moodle_database extends moodle_database {
     /**
      * Does this driver support tool_replace?
      *
-     * @since 2.6.1
+     * @since Moodle 2.6.1
      * @return bool
      */
     public function replace_all_text_supported() {
index 5838292..7890323 100644 (file)
@@ -100,7 +100,6 @@ class atto_texteditor extends texteditor {
             foreach ($plugins as $plugin) {
                 // Do not die on missing plugin.
                 if (!core_component::get_component_directory('atto_' . $plugin))  {
-                    debugging('Missing atto plugin ' . $plugin, DEBUG_DEVELOPER);
                     continue;
                 }
 
index b91ba66..c3740bf 100644 (file)
Binary files a/lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button-debug.js and b/lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button-debug.js differ
index 0c5ced7..5098939 100644 (file)
Binary files a/lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button-min.js and b/lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button-min.js differ
index 6911aa8..ee97f23 100644 (file)
Binary files a/lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button.js and b/lib/editor/atto/plugins/collapse/yui/build/moodle-atto_collapse-button/moodle-atto_collapse-button.js differ
index 6d0d427..0576996 100644 (file)
@@ -79,8 +79,10 @@ Y.namespace('M.atto_collapse').Button = Y.Base.create('button', Y.M.editor_atto.
         var button = this.buttons[COLLAPSE];
 
         if (button.getData(COLLAPSED)) {
+            this.highlightButtons(COLLAPSE);
             this._setVisibility(button, true);
         } else {
+            this.unHighlightButtons(COLLAPSE);
             this._setVisibility(button);
         }
 
index 32233da..8e19cb2 100644 (file)
Binary files a/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-button/moodle-atto_html-button-debug.js and b/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-button/moodle-atto_html-button-debug.js differ
index d974624..0b9d2ea 100644 (file)
Binary files a/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-button/moodle-atto_html-button-min.js and b/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-button/moodle-atto_html-button-min.js differ
index 32233da..8e19cb2 100644 (file)
Binary files a/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-button/moodle-atto_html-button.js and b/lib/editor/atto/plugins/html/yui/build/moodle-atto_html-button/moodle-atto_html-button.js differ
index b4b8132..9c65d86 100644 (file)
@@ -64,6 +64,9 @@ Y.namespace('M.atto_html').Button = Y.Base.create('button', Y.M.editor_atto.Edit
     _showHTML: function() {
         var host = this.get('host');
         if (!this.get('isHTML')) {
+            // Unhighlight icon.
+            this.unHighlightButtons('html');
+
             // Enable all plugins.
             host.enablePlugins();
 
@@ -80,6 +83,9 @@ Y.namespace('M.atto_html').Button = Y.Base.create('button', Y.M.editor_atto.Edit
             // And re-mark everything as updated.
             this.markUpdated();
         } else {
+            // Highlight icon.
+            this.highlightButtons('html');
+
             // Disable all plugins.
             host.disablePlugins();
 
@@ -89,10 +95,19 @@ Y.namespace('M.atto_html').Button = Y.Base.create('button', Y.M.editor_atto.Edit
             // Copy the text to the contenteditable div.
             host.updateOriginal();
 
+            // Get the width, padding, and margin of the editor.
+            host.textarea.setStyles({
+                'width': this.editor.getComputedStyle('width'),
+                'height': this.editor.getComputedStyle('height'),
+                'margin': this.editor.getComputedStyle('margin'),
+                'padding': this.editor.getComputedStyle('padding')
+            });
+
             // Hide the editor, and show the textarea.
             this.editor.hide();
             host.textarea.show();
 
+
             // Focus on the textarea.
             host.textarea.focus();
         }
index 3d9ee6a..95a6b97 100644 (file)
@@ -1,10 +1,13 @@
 .atto_image_preview {
-    max-width: 150px;
-    max-height: 150px;
+    width: 100%;
+    height: 100%;
+    margin-left: auto;
+    margin-right: auto;
 }
 .atto_image_preview_box {
-    height: 150px;
+    max-height: 200px;
     margin-bottom: 1em;
+    overflow: auto;
 }
 
 .editor_atto_content img {
index b92532c..24abed2 100644 (file)
Binary files a/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-debug.js and b/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-debug.js differ
index df9ace1..cf58442 100644 (file)
Binary files a/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-min.js and b/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button-min.js differ
index b92532c..24abed2 100644 (file)
Binary files a/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button.js and b/lib/editor/atto/plugins/image/yui/build/moodle-atto_image-button/moodle-atto_image-button.js differ
index c34a748..eba4d81 100644 (file)
@@ -148,9 +148,8 @@ var CSS = {
                 // Add the image preview.
                 '<div class="mdl-align">' +
                 '<div class="{{CSS.IMAGEPREVIEWBOX}}">' +
-                '<img src="#" class="{{CSS.IMAGEPREVIEW}}" id="{{elementid}}_{{CSS.IMAGEPREVIEW}}" alt="" style="display: none;"/>' +
+                    '<img src="#" class="{{CSS.IMAGEPREVIEW}}" alt="" style="display: none;"/>' +
                 '</div>' +
-                '<br/>' +
 
                 // Add the submit button and close the form.
                 '<button class="{{CSS.INPUTSUBMIT}}" type="submit">{{get_string "saveimage" component}}</button>' +
@@ -196,22 +195,13 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
     _form: null,
 
     /**
-     * Remember the image true dimensions so we can constrain resizing.
-     *
-     * @param _imageRawWidth
-     * @type Integer
-     * @private
-     */
-    _imageRawWidth: 0,
-
-    /**
-     * Remember the image true dimensions so we can constrain resizing.
+     * The dimensions of the raw image before we manipulate it.
      *
-     * @param _imageRawHeight
-     * @type Integer
+     * @param _rawImageDimensions
+     * @type Object
      * @private
      */
-    _imageRawHeight: 0,
+    _rawImageDimensions: null,
 
     initializer: function() {
         this.addButton({
@@ -274,11 +264,23 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
     _loadPreviewImage: function(url) {
         var image = new Image(), self = this;
 
+        image.onerror = function() {
+            var preview = self._form.one('.' + CSS.IMAGEPREVIEW);
+            preview.setStyles({
+                'display': 'none'
+            });
+
+            // Centre the dialogue when clearing the image preview.
+            self.getDialogue().centerDialogue();
+        };
+
         image.onload = function() {
             var input, currentwidth, currentheight, widthRatio, heightRatio;
 
-            self._imageRawWidth = this.width;
-            self._imageRawHeight = this.height;
+            self._rawImageDimensions = {
+                width: this.width,
+                height: this.height
+            };
 
             input = self._form.one('.' + CSS.INPUTWIDTH);
             currentwidth = input.get('value');
@@ -293,8 +295,10 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
                 currentheight = "" + this.height;
             }
             input = self._form.one('.' + CSS.IMAGEPREVIEW);
-            input.set('src', this.src);
-            input.setStyle('display', 'inline');
+            input.setAttribute('src', this.src);
+            input.setStyles({
+                'display': 'inline'
+            });
 
             input = self._form.one('.' + CSS.INPUTCONSTRAIN);
             if (currentwidth.match(REGEX.ISPERCENT) && currentheight.match(REGEX.ISPERCENT)) {
@@ -312,6 +316,9 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
                 input.set('checked', widthRatio === heightRatio);
             }
 
+            // Apply the image sizing.
+            self._autoAdjustSize(self);
+
             // Centre the dialogue once the preview image has loaded.
             self.getDialogue().centerDialogue();
         };
@@ -346,11 +353,11 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
         this._form.one('.' + CSS.INPUTURL).on('blur', this._urlChanged, this);
         this._form.one('.' + CSS.IMAGEPRESENTATION).on('change', this._updateWarning, this);
         this._form.one('.' + CSS.INPUTALT).on('change', this._updateWarning, this);
-        this._form.one('.' + CSS.INPUTWIDTH).on('blur', this._autoAdjustHeight, this);
-        this._form.one('.' + CSS.INPUTHEIGHT).on('blur', this._autoAdjustWidth, this);
+        this._form.one('.' + CSS.INPUTWIDTH).on('blur', this._autoAdjustSize, this);
+        this._form.one('.' + CSS.INPUTHEIGHT).on('blur', this._autoAdjustSize, this, true);
         this._form.one('.' + CSS.INPUTCONSTRAIN).on('change', function(event) {
             if (event.target.get('checked')) {
-                this._autoAdjustHeight();
+                this._autoAdjustSize(event);
             }
         }, this);
         this._form.one('.' + CSS.INPUTURL).on('blur', this._urlChanged, this);
@@ -365,84 +372,104 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
         return content;
     },
 
-    /**
-     * Adjust the height to keep the aspect ratio.
-     *
-     * @method _autoAdjustHeight
-     * @private
-     */
-    _autoAdjustHeight: function() {
-        var currentWidth, newHeight, currentHeight;
+    _autoAdjustSize: function(e, forceHeight) {
+        forceHeight = forceHeight || false;
+
+        var keyField = this._form.one('.' + CSS.INPUTWIDTH),
+            keyFieldType = 'width',
+            subField = this._form.one('.' + CSS.INPUTHEIGHT),
+            subFieldType = 'height',
+            constrainField = this._form.one('.' + CSS.INPUTCONSTRAIN),
+            keyFieldValue = keyField.get('value'),
+            subFieldValue = subField.get('value'),
+            imagePreview = this._form.one('.' + CSS.IMAGEPREVIEW),
+            rawPercentage,
+            rawSize;
 
         // Set the width back to default if it is empty.
-        if (this._form.one('.' + CSS.INPUTWIDTH).get('value') === '') {
-            this._form.one('.' + CSS.INPUTWIDTH).set('value', this._imageRawWidth);
+        if (keyFieldValue === '') {
+            keyFieldValue = this._rawImageDimensions[keyFieldType];
+            keyField.set('value', keyFieldValue);
+            keyFieldValue = keyField.get('value');
         }
 
-        if (!this._form.one('.' + CSS.INPUTCONSTRAIN).get('checked')) {
-            currentWidth = this._form.one('.' + CSS.INPUTWIDTH).get('value');
-            currentHeight = this._form.one('.' + CSS.INPUTHEIGHT).get('value');
-            this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', currentHeight);
-            this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', currentWidth);
-            return;
-        }
+        // Clear the existing preview sizes.
+        imagePreview.setStyles({
+            width: null,
+            height: null
+        });
 
-        currentWidth = this._form.one('.' + CSS.INPUTWIDTH).get('value').trim();
-        // If this is a percentage based width, copy it verbatim to the height.
-        if (currentWidth.match(REGEX.ISPERCENT)) {
-            newHeight = currentWidth;
-            this._form.one('.' + CSS.INPUTHEIGHT).set('value', newHeight);
-            this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', newHeight);
-            this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', currentWidth);
-        } else {
-            currentWidth = parseInt(this._form.one('.' + CSS.INPUTWIDTH).get('value'), 10);
-            newHeight = Math.round((currentWidth / this._imageRawWidth) * this._imageRawHeight);
+        // Now update with the new values.
+        if (!constrainField.get('checked')) {
+            // We are not keeping the image proportion - update the preview accordingly.
 
-            if (!isNaN(newHeight)) {
-                this._form.one('.' + CSS.INPUTHEIGHT).set('value', newHeight);
-                this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', newHeight);
-                this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', currentWidth);
+            // Width.
+            if (keyFieldValue.match(REGEX.ISPERCENT)) {
+                rawPercentage = parseInt(keyFieldValue, 10);
+                rawSize = this._rawImageDimensions.width / 100 * rawPercentage;
+                imagePreview.setStyle('width', rawSize + 'px');
+            } else {
+                imagePreview.setStyle('width', keyFieldValue + 'px');
             }
-        }
-    },
 
-    /**
-     * Adjust the width to keep the aspect ratio.
-     *
-     * @method _autoAdjustWidth
-     * @private
-     */
-    _autoAdjustWidth: function() {
-        var currentHeight, newWidth;
+            // Height.
+            if (subFieldValue.match(REGEX.ISPERCENT)) {
+                rawPercentage = parseInt(subFieldValue, 10);
+                rawSize = this._rawImageDimensions.height / 100 * rawPercentage;
+                imagePreview.setStyle('height', rawSize + 'px');
+            } else {
+                imagePreview.setStyle('height', subFieldValue + 'px');
+            }
+        } else {
+            // We are keeping the image in proportion.
+            if (forceHeight) {
+                // By default we update based on width. Swap the key and sub fields around to achieve a height-based scale.
+                var _temporaryValue;
+                _temporaryValue = keyField;
+                keyField = subField;
+                subField = _temporaryValue;
+
+                _temporaryValue = keyFieldType;
+                keyFieldType = subFieldType;
+                subFieldType = _temporaryValue;
+
+                _temporaryValue = keyFieldValue;
+                keyFieldValue = subFieldValue;
+                subFieldValue = _temporaryValue;
+            }
 
-        // Set the height back to default if it is empty.
-        if (this._form.one('.' + CSS.INPUTHEIGHT).get('value') === '') {
-            this._form.one('.' + CSS.INPUTHEIGHT).set('value', this._imageRawHeight);
-        }
+            if (keyFieldValue.match(REGEX.ISPERCENT)) {
+                // This is a percentage based change. Copy it verbatim.
+                subFieldValue = keyFieldValue;
 
-        if (!this._form.one('.' + CSS.INPUTCONSTRAIN).get('checked')) {
-            currentWidth = this._form.one('.' + CSS.INPUTWIDTH).get('value');
-            currentHeight = this._form.one('.' + CSS.INPUTHEIGHT).get('value');
-            this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', currentHeight);
-            this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', currentWidth);
-            return;
-        }
-        currentHeight = this._form.one('.' + CSS.INPUTHEIGHT).get('value').trim();
-        // If this is a percentage based width, copy it verbatim to the height.
-        if (currentHeight.match(REGEX.ISPERCENT)) {
-            newWidth = currentHeight;
-            this._form.one('.' + CSS.INPUTWIDTH).set('value', newWidth);
-            this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', newWidth);
-            this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', currentHeight);
-        } else {
-            currentHeight = parseInt(this._form.one('.' + CSS.INPUTHEIGHT).get('value'), 10);
-            newWidth = Math.round((currentHeight / this._imageRawHeight) * this._imageRawWidth);
+                // Set the width to the calculated pixel width.
+                rawPercentage = parseInt(keyFieldValue, 10);
+                rawSize = this._rawImageDimensions.width / 100 * rawPercentage;
 
-            if (!isNaN(newWidth)) {
-                this._form.one('.' + CSS.INPUTWIDTH).set('value', newWidth);
-                this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', newWidth);
-                this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', currentHeight);
+                // And apply the width/height to the container.
+                imagePreview.setStyle('width', rawSize);
+                rawSize = this._rawImageDimensions.height / 100 * rawPercentage;
+                imagePreview.setStyle('height', rawSize);
+            } else {
+                // Calculate the scaled subFieldValue from the keyFieldValue.
+                subFieldValue = Math.round((keyFieldValue / this._rawImageDimensions[keyFieldType]) *
+                        this._rawImageDimensions[subFieldType]);
+
+                if (forceHeight) {
+                    imagePreview.setStyles({
+                        'width': subFieldValue,
+                        'height': keyFieldValue
+                    });
+                } else {
+                    imagePreview.setStyles({
+                        'width': keyFieldValue,
+                        'height': subFieldValue
+                    });
+                }
             }
+
+            // Update the subField's value within the form to reflect the changes.
+            subField.set('value', subFieldValue);
         }
     },
 
@@ -504,9 +531,6 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
         if (properties.customstyle) {
             form.one('.' + CSS.INPUTCUSTOMSTYLE).set('value', properties.customstyle);
         }
-        if (properties.display) {
-            img.setStyle('display', properties.display);
-        }
         if (properties.width) {
             form.one('.' + CSS.INPUTWIDTH).set('value', properties.width);
         }
@@ -523,6 +547,9 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
         if (properties.presentation) {
             form.one('.' + CSS.IMAGEPRESENTATION).set('checked', 'checked');
         }
+
+        // Update the image preview based on the form properties.
+        this._autoAdjustSize();
     },
 
     /**
@@ -541,7 +568,6 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
                 width: null,
                 height: null,
                 align: '',
-                display: 'inline',
                 presentation: false
             },
 
index 81ceac4..9236504 100644 (file)
Binary files a/lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button-debug.js and b/lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button-debug.js differ
index c93d216..818481e 100644 (file)
Binary files a/lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button-min.js and b/lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button-min.js differ
index f13bced..9236504 100644 (file)
Binary files a/lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button.js and b/lib/editor/atto/plugins/undo/yui/build/moodle-atto_undo-button/moodle-atto_undo-button.js differ
index 026e4a2..0a5baf5 100644 (file)
@@ -122,10 +122,6 @@ Y.namespace('M.atto_undo').Button = Y.Base.create('button', Y.M.editor_atto.Edit
             clearRedo = false;
         }
 
-        if (typeof last === 'undefined') {
-            Y.log('Oops, nothing was in the undo stack! There should always be something in there.', 'warn', LOGNAME);
-        }
-
         if (last !== html) {
             this._undoStack.push(html);
             if (clearRedo) {
index f3406c9..7772759 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-debug.js differ
index 00dd307..2c2b5b1 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor-min.js differ
index 950764d..6f2c68a 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js and b/lib/editor/atto/yui/build/moodle-editor_atto-editor/moodle-editor_atto-editor.js differ
index 72171dd..3adfbd4 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-plugin/moodle-editor_atto-plugin-debug.js and b/lib/editor/atto/yui/build/moodle-editor_atto-plugin/moodle-editor_atto-plugin-debug.js differ
index 0229028..01dfab6 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-plugin/moodle-editor_atto-plugin-min.js and b/lib/editor/atto/yui/build/moodle-editor_atto-plugin/moodle-editor_atto-plugin-min.js differ
index 07f3f1a..963a932 100644 (file)
Binary files a/lib/editor/atto/yui/build/moodle-editor_atto-plugin/moodle-editor_atto-plugin.js and b/lib/editor/atto/yui/build/moodle-editor_atto-plugin/moodle-editor_atto-plugin.js differ
index 1a052d6..89ccac7 100644 (file)
@@ -42,7 +42,8 @@ EditorClean.prototype = {
      */
     getCleanHTML: function() {
         // Clone the editor so that we don't actually modify the real content.
-        var editorClone = this.editor.cloneNode(true);
+        var editorClone = this.editor.cloneNode(true),
+            html;
 
         // Remove all YUI IDs.
         Y.each(editorClone.all('[id^="yui"]'), function(node) {
@@ -50,9 +51,15 @@ EditorClean.prototype = {
         });
 
         editorClone.all('.atto_control').remove(true);
+        html = editorClone.get('innerHTML');
+
+        // Revert untouched editor contents to an empty string.
+        if (html === '<p></p>' || html === '<p><br></p>') {
+            return '';
+        }
 
         // Remove any and all nasties from source.
-       return this._cleanHTML(editorClone.get('innerHTML'));
+       return this._cleanHTML(html);
     },
 
     /**
index fb2a931..6804837 100644 (file)
@@ -602,7 +602,11 @@ EditorPluginButtons.prototype = {
             return;
         }
 
-        if (!this.get('host').isActive()) {
+        if (!(YUI.Env.UA.android || this.get('host').isActive())) {
+            // We must not focus for Android here, even if the editor is not active because the keyboard auto-completion
+            // changes the cursor position.
+            // If we save that change, then when we restore the change later we get put in the wrong place.
+            // Android is fine to save the selection without the editor being in focus.
             this.get('host').focus();
         }
 
index ee24e5a..b83bc16 100644 (file)
@@ -199,6 +199,11 @@ Y.extend(Editor, Y.Base, {
         // Disable odd inline CSS styles.
         this.disableCssStyling();
 
+        // Use paragraphs not divs.
+        if (document.queryCommandSupported('DefaultParagraphSeparator')) {
+            document.execCommand('DefaultParagraphSeparator', false, 'p');
+        }
+
         // Add the toolbar and editable zone to the page.
         this.textarea.get('parentNode').insert(this._wrapper, this.textarea);
 
index c0b4a3c..08e1a25 100644 (file)
@@ -120,6 +120,11 @@ EditorSelection.prototype = {
             return false;
         }
 
+        // We can't be active if the editor doesn't have focus at the moment.
+        if (!document.activeElement || Y.one(document.activeElement) !== this.editor) {
+            return false;
+        }
+
         // Check whether the range intersects the editor selection.
         range.selectNode(this.editor.getDOMNode());
         return range.intersectsRange(selection.getRangeAt(0));
@@ -148,9 +153,7 @@ EditorSelection.prototype = {
      * @method saveSelection
      */
     saveSelection: function() {
-        if (this.isActive()) {
-            this._selections = this.getSelection();
-        }
+        this._selections = this.getSelection();
     },
 
     /**
@@ -272,7 +275,10 @@ EditorSelection.prototype = {
         if (range.collapsed) {
             // We do not want to select all the nodes in the editor if we managed to
             // have a collapsed selection directly in the editor.
-            if (range.commonAncestorContainer !== this.editor.getDOMNode()) {
+            // It's also possible for the commonAncestorContainer to be the document, which selectNode does not handle
+            // so we must filter that out here too.
+            if (range.commonAncestorContainer !== this.editor.getDOMNode()
+                    && range.commonAncestorContainer !== Y.config.doc) {
                 range = range.cloneRange();
                 range.selectNode(range.commonAncestorContainer);
             }
index c69681d..b0897db 100644 (file)
@@ -45,7 +45,7 @@ class core_external extends external_api {
      *
      * @param array $stringparams
      * @return object|string
-     * @since 2.4
+     * @since Moodle 2.4
      */
     public static function format_string_parameters($stringparams) {
         // Check if there are some string params.
index ad701b2..2ce6de6 100644 (file)
@@ -694,7 +694,7 @@ class external_format_value extends external_value {
  * @param array $format the format to validate
  * @return the validated format
  * @throws coding_exception
- * @since 2.3
+ * @since Moodle 2.3
  */
 function external_validate_format($format) {
     $allowedformats = array(FORMAT_HTML, FORMAT_MOODLE, FORMAT_PLAIN, FORMAT_MARKDOWN);
index d45b13d..6e1b9f6 100644 (file)
@@ -541,7 +541,7 @@ function file_get_draft_area_info($draftitemid, $filepath = '/') {
  * @param int $newfilesize the size that would be added to the current area.
  * @param bool $includereferences true to include the size of the references in the area size.
  * @return bool true if the area will/has exceeded its limit.
- * @since 2.4
+ * @since Moodle 2.4
  */
 function file_is_draft_area_limit_reached($draftitemid, $areamaxbytes, $newfilesize = 0, $includereferences = false) {
     if ($areamaxbytes != FILE_AREA_MAX_BYTES_UNLIMITED) {
index 299dbb2..32fec85 100644 (file)
@@ -199,7 +199,7 @@ class file_storage {
      * @param string $filename the file name.
      * @return string available file name.
      * @throws coding_exception if the file name is invalid.
-     * @since 2.5
+     * @since Moodle 2.5
      */
     public function get_unused_filename($contextid, $component, $filearea, $itemid, $filepath, $filename) {
         global $DB;
@@ -280,7 +280,7 @@ class file_storage {
      * @param int $itemid area item ID.
      * @param string $suggestedpath the suggested file path.
      * @return string available file path
-     * @since 2.5
+     * @since Moodle 2.5
      */
     public function get_unused_dirname($contextid, $component, $filearea, $itemid, $suggestedpath) {
         global $DB;
index 5aca116..f47d6ce 100644 (file)
@@ -247,7 +247,7 @@ class filter_manager {
      *
      * @param moodle_page $page the page we are going to add requirements to.
      * @param context $context the context which contents are going to be filtered.
-     * @since 2.3
+     * @since Moodle 2.3
      */
     public function setup_page_for_filters($page, $context) {
         $filters = $this->get_text_filters($context);
@@ -409,7 +409,7 @@ abstract class moodle_text_filter {
      *
      * @param moodle_page $page the page we are going to add requirements to.
      * @param context $context the context which contents are going to be filtered.
-     * @since 2.3
+     * @since Moodle 2.3
      */
     public function setup($page, $context) {
         // Override me, if needed.
index 57bbd94..97a0219 100644 (file)
@@ -67,7 +67,7 @@ class MoodleQuickForm_text extends HTML_QuickForm_text{
     /**
      * Freeze the element so that only its value is returned and set persistantfreeze to false
      *
-     * @since     2.4
+     * @since     Moodle 2.4
      * @access    public
      * @return    void
      */
@@ -81,7 +81,7 @@ class MoodleQuickForm_text extends HTML_QuickForm_text{
     /**
      * Returns the html to be used when the element is frozen
      *
-     * @since     2.4
+     * @since     Moodle 2.4
      * @return    string Frozen html
      */
     function getFrozenHtml()
index f3da219..75a76c0 100644 (file)
@@ -183,7 +183,7 @@ class moodle_google_curlio extends Google_CurlIO {
      * @param int $constant value of a CURL constant.
      * @return string name of the constant if found, or throws exception.
      * @throws coding_exception when the constant is not found.
-     * @since 2.5
+     * @since Moodle 2.5
      */
     public function get_option_name_from_constant($constant) {
         if (is_null(self::$constants)) {
index 3ad3a6a..75a6f20 100644 (file)
@@ -1455,7 +1455,7 @@ function grade_floats_different($f1, $f2) {
  * Do not use rounding for 10,5 at the database level as the results may be
  * different from php round() function.
  *
- * @since 2.0
+ * @since Moodle 2.0
  * @param float $f1 Float one to compare
  * @param float $f2 Float two to compare
  * @return bool True if the values should be considered as the same grades
index 5cd4c3d..e493437 100644 (file)
@@ -19,7 +19,7 @@
 /**
  * A namespace contains license specific functions
  *
- * @since      2.0
+ * @since      Moodle 2.0
  * @package    core
  * @subpackage lib
  * @copyright  2010 Dongsheng Cai <dongsheng@moodle.com>
index 36dfc72..3b76dd9 100644 (file)
@@ -2174,7 +2174,7 @@ function userdate($date, $format = '', $timezone = 99, $fixday = true, $fixhour
  * @param string $format strftime format.
  * @param int|float $tz the numerical timezone, typically returned by {@link get_user_timezone_offset()}.
  * @return string the formatted date/time.
- * @since 2.3.3
+ * @since Moodle 2.3.3
  */
 function date_format_string($date, $format, $tz = 99) {
     global $CFG;
@@ -5796,6 +5796,14 @@ function email_to_user($user, $from, $subject, $messagetext, $messagehtml = '',
         $mail->Sender = $supportuser->email;
     }
 
+    if (!empty($CFG->emailonlyfromnoreplyaddress)) {
+        $usetrueaddress = false;
+        if (empty($replyto) && $from->maildisplay) {
+            $replyto = $from->email;
+            $replytoname = fullname($from);
+        }
+    }
+
     if (is_string($from)) { // So we can pass whatever we want if there is need.
         $mail->From     = $CFG->noreplyaddress;
         $mail->FromName = $from;
index 06081c0..b0f14f1 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * This file contains classes used to manage the navigation structures within Moodle.
  *
- * @since      2.0
+ * @since      Moodle 2.0
  * @package    core
  * @copyright  2009 Sam Hemelryk
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
@@ -697,7 +697,7 @@ class navigation_node implements renderable {
     /**
      * Hides the node and any children it has.
      *
-     * @since 2.5
+     * @since Moodle 2.5
      * @param array $typestohide Optional. An array of node types that should be hidden.
      *      If null all nodes will be hidden.
      *      If an array is given then nodes will only be hidden if their type mtatches an element in the array.
@@ -1323,7 +1323,7 @@ class global_navigation extends navigation_node {
      * other user being viewed this function returns false.
      * In order to set the user for whom we are checking against you must call {@link set_userid_for_parent_checks()}
      *
-     * @since 2.4
+     * @since Moodle 2.4
      * @return bool
      */
     protected function current_user_is_parent_role() {
@@ -2769,6 +2769,12 @@ class global_navigation_for_ajax extends global_navigation {
                 break;
             case self::TYPE_COURSE :
                 $course = $DB->get_record('course', array('id' => $this->instanceid), '*', MUST_EXIST);
+                if (!can_access_course($course)) {
+                    // Thats OK all courses are expandable by default. We don't need to actually expand it we can just
+                    // add the course node and break. This leads to an empty node.
+                    $this->add_course($course);
+                    break;
+                }
                 require_course_login($course, true, null, false, true);
                 $this->page->set_context(context_course::instance($course->id));
                 $coursenode = $this->add_course($course);
index cf1aaa9..b31a2ac 100644 (file)
@@ -645,7 +645,7 @@ class core_renderer extends renderer_base {
                 $loggedinas = get_string('loggedinas', 'moodle', $username).$rolename;
                 if ($withlinks) {
                     $url = new moodle_url('/course/switchrole.php', array('id'=>$course->id,'sesskey'=>sesskey(), 'switchrole'=>0, 'returnurl'=>$this->page->url->out_as_local_url(false)));
-                    $loggedinas .= '('.html_writer::tag('a', get_string('switchrolereturn'), array('href'=>$url)).')';
+                    $loggedinas .= ' ('.html_writer::tag('a', get_string('switchrolereturn'), array('href' => $url)).')';
                 }
             } else {
                 $loggedinas = $realuserinfo.get_string('loggedinas', 'moodle', $username);
@@ -3224,7 +3224,7 @@ EOD;
     /**
      * Get the HTML for blocks in the given region.
      *
-     * @since 2.5.1 2.6
+     * @since Moodle 2.5.1 2.6
      * @param string $region The region to get HTML for.
      * @return string HTML.
      */
@@ -3271,7 +3271,7 @@ EOD;
     /**
      * Returns the CSS classes to apply to the body tag.
      *
-     * @since 2.5.1 2.6
+     * @since Moodle 2.5.1 2.6
      * @param array $additionalclasses Any additional classes to apply.
      * @return string
      */
@@ -3301,7 +3301,7 @@ EOD;
     /**
      * The ID attribute to apply to the body tag.
      *
-     * @since 2.5.1 2.6
+     * @since Moodle 2.5.1 2.6
      * @return string
      */
     public function body_id() {
@@ -3311,7 +3311,7 @@ EOD;
     /**
      * Returns HTML attributes to use within the body tag. This includes an ID and classes.
      *
-     * @since 2.5.1 2.6
+     * @since Moodle 2.5.1 2.6
      * @param string|array $additionalclasses Any additional classes to give the body tag,
      * @return string
      */
@@ -3325,7 +3325,7 @@ EOD;
     /**
      * Gets HTML for the page heading.
      *
-     * @since 2.5.1 2.6
+     * @since Moodle 2.5.1 2.6
      * @param string $tag The tag to encase the heading in. h1 by default.
      * @return string HTML.
      */
@@ -3336,7 +3336,7 @@ EOD;
     /**
      * Gets the HTML for the page heading button.
      *
-     * @since 2.5.1 2.6
+     * @since Moodle 2.5.1 2.6
      * @return string HTML.
      */
     public function page_heading_button() {
@@ -3346,7 +3346,7 @@ EOD;
     /**
      * Returns the Moodle docs link to use for this page.
      *
-     * @since 2.5.1 2.6
+     * @since Moodle 2.5.1 2.6
      * @param string $text
      * @return string
      */
@@ -3364,7 +3364,7 @@ EOD;
     /**
      * Returns the page heading menu.
      *
-     * @since 2.5.1 2.6
+     * @since Moodle 2.5.1 2.6
      * @return string HTML.
      */
     public function page_heading_menu() {
@@ -3374,7 +3374,7 @@ EOD;
     /**
      * Returns the title to use on the page.
      *
-     * @since 2.5.1 2.6
+     * @since Moodle 2.5.1 2.6
      * @return string
      */
     public function page_title() {
@@ -3384,7 +3384,7 @@ EOD;
     /**
      * Returns the URL for the favicon.
      *
-     * @since 2.5.1 2.6
+     * @since Moodle 2.5.1 2.6
      * @return string The favicon URL
      */
     public function favicon() {
@@ -3853,7 +3853,7 @@ class core_media_renderer extends plugin_renderer_base {
  * is running a maintenance related task.
  * It must always extend the core_renderer as we switch from the core_renderer to this renderer in a couple of places.
  *
- * @since 2.6
+ * @since Moodle 2.6
  * @package core
  * @category output
  * @copyright 2013 Sam Hemelryk
index 74049b6..01700af 100644 (file)
@@ -745,7 +745,7 @@ class page_requirements_manager {
                                     'requires' => array('node', 'event', 'json', 'core_filepicker'),
                                     'strings'  => array(array('uploadformlimit', 'moodle'), array('droptoupload', 'moodle'), array('maxfilesreached', 'moodle'),
                                                         array('dndenabled_inbox', 'moodle'), array('fileexists', 'moodle'), array('maxbytesforfile', 'moodle'),
-                                                        array('maxareabytesreached', 'moodle')
+                                                        array('maxareabytesreached', 'moodle'), array('serverconnection', 'error'),
                                                     ));
                     break;
             }
@@ -1433,6 +1433,15 @@ class page_requirements_manager {
         }
 
         // Add all needed strings.
+        // First add core strings required for some dialogues.
+        $this->strings_for_js(array(
+            'confirm',
+            'yes',
+            'no',
+            'areyousure',
+            'closebuttontitle',
+            'unknownerror',
+        ), 'moodle');
         if (!empty($this->stringsforjs)) {
             $strings = array();
             foreach ($this->stringsforjs as $component=>$v) {
index 3aae32f..c650dad 100644 (file)
@@ -642,7 +642,7 @@ class moodle_page {
     /**
      * Returns an array of minipulations or false if there are none to make.
      *
-     * @since 2.5.1 2.6
+     * @since Moodle 2.5.1 2.6
      * @return bool|array
      */
     protected function magic_get_blockmanipulations() {
@@ -1906,7 +1906,7 @@ class moodle_page {
     /**
      * Returns the block region having made any required theme manipulations.
      *
-     * @since 2.5.1 2.6
+     * @since Moodle 2.5.1 2.6
      * @param string $region
      * @return string
      */
index 1405ff1..cd2048b 100644 (file)
@@ -134,7 +134,7 @@ class pdf extends TCPDF {
      * @param $name (string) The name of the file when saved. Note that special characters are removed and blanks characters are replaced with the underscore character.
      * @param $dest (string) Destination where to send the document. It can take one of the following values:<ul><li>I: send the file inline to the browser (default). The plug-in is used if available. The name given by name is used when one selects the "Save as" option on the link generating the PDF.</li><li>D: send to the browser and force a file download with the name given by name.</li><li>F: save to a local server file with the name given by name.</li><li>S: return the document as a string (name is ignored).</li><li>FI: equivalent to F + I option</li><li>FD: equivalent to F + D option</li><li>E: return the document as base64 mime multi-part email attachment (RFC 2045)</li></ul>
      * @public
-     * @since 1.0
+     * @since Moodle 1.0
      * @see Close()
      */
     public function Output($name='doc.pdf', $dest='I') {
index c12d181..af30367 100644 (file)
@@ -112,8 +112,8 @@ class phpunit_util extends testing_util {
         // Stop any message redirection.
         phpunit_util::stop_event_redirection();
 
-        // Release memory and indirectly call destroy() methods to release resource handles, etc.
-        gc_collect_cycles();
+        // We used to call gc_collect_cycles here to ensure desctructors were called between tests.
+        // This accounted for 25% of the total time running phpunit - so we removed it.
 
         // Show any unhandled debugging messages, the runbare() could already reset it.
         self::display_debugging_messages();
index 566587d..1c28f17 100644 (file)
@@ -18,7 +18,7 @@
 /**
  * plagiarismlib.php - Contains core Plagiarism related functions.
  *
- * @since 2.0
+ * @since Moodle 2.0
  * @package    moodlecore
  * @subpackage plagiarism
  * @copyright  2010 Dan Marsden http://danmarsden.com
index ea316a7..67e44be 100644 (file)
@@ -588,7 +588,7 @@ EOD;
      * @param array|stdClass $record data to use to up set the instance.
      * @param array $options options
      * @return stdClass repository instance record
-     * @since 2.5.1
+     * @since Moodle 2.5.1
      */
     public function create_repository($type, $record=null, array $options = null) {
         $generator = $this->get_plugin_generator('repository_'.$type);
@@ -602,7 +602,7 @@ EOD;
      * @param array|stdClass $record data to use to up set the instance.
      * @param array $options options
      * @return repository_type object
-     * @since 2.5.1
+     * @since Moodle 2.5.1
      */
     public function create_repository_type($type, $record=null, array $options = null) {
         $generator = $this->get_plugin_generator('repository_'.$type);
index e190a59..3d5f560 100644 (file)
@@ -32,7 +32,7 @@ defined('MOODLE_INTERNAL') || die();
  * @category   test
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- * @since      2.5.1
+ * @since      Moodle 2.5.1
  */
 class testing_repository_generator extends component_generator_base {
 
index edf1e50..99ce17b 100644 (file)
@@ -282,6 +282,18 @@ class behat_general extends behat_base {
         $node->click();
     }
 
+    /**
+     * Clicks the specified element and confirms the expected dialogue.
+     *
+     * @When /^I click on "(?P<element_string>(?:[^"]|\\")*)" "(?P<selector_string>[^"]*)" confirming the dialogue$/
+     * @throws ElementNotFoundException Thrown by behat_base::find
+     * @param string $link
+     */
+    public function i_click_on_confirming_the_dialogue($element, $selectortype) {
+        $this->i_click_on($element, $selectortype);
+        $this->accept_currently_displayed_alert_dialog();
+    }
+
     /**
      * Click on the element of the specified type which is located inside the second element.
      *
@@ -810,9 +822,9 @@ class behat_general extends behat_base {
                     return $context->getSession()->getPage()->findAll($args['selector'], $args['locator']);
                 },
                 $params,
-                false,
+                self::REDUCED_TIMEOUT,
                 $exception,
-                self::REDUCED_TIMEOUT
+                false
             );
 
             throw new ExpectationException('The "' . $element . '" "' . $selectortype . '" exists in the current page', $this->getSession());
index 4d9271b..5054435 100644 (file)
@@ -40,12 +40,108 @@ use Behat\Behat\Context\Step\Given as Given,
  */
 class behat_navigation extends behat_base {
 
+    /**
+     * Helper function to get a navigation nodes text element given its text from within the navigation block.
+     *
+     * This function finds the node with the given text from within the navigation block.
+     * It checks to make sure the node is visible, and then returns it.
+     *
+     * @param string $text
+     * @param bool $branch Set this true if you're only interested in the node if its a branch.
+     * @param null|bool $collapsed Set this to true or false if you want the node to either be collapsed or not.
+     *    If its left as null then we don't worry about it.
+     * @param null|string|Exception|false $exception The exception to throw if the node is not found.
+     * @return \Behat\Mink\Element\NodeElement
+     */
+    protected function get_node_text_node($text, $branch = false, $collapsed = null, $exception = null) {
+        if ($exception === null) {
+            $exception = new ExpectationException('The "' . $text . '" node could not be found', $this->getSession());
+        } else if (is_string($exception)) {
+            $exception = new ExpectationException($exception, $this->getSession());
+        }
+
+        $nodetextliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($text);
+        $hasblocktree = "[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]";
+        $hasbranch = "[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]";
+        $hascollapsed = "li[contains(concat(' ', normalize-space(@class), ' '), ' collapsed ') or @data-expandable='1']";
+        $notcollapsed = "li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed '))]";
+        $match = "[normalize-space(.)={$nodetextliteral}]";
+
+        // Avoid problems with quotes.
+        $isbranch = ($branch) ? $hasbranch : '';
+        if ($collapsed === true) {
+            $iscollapsed = $hascollapsed;
+        } else if ($collapsed === false) {
+            $iscollapsed = $notcollapsed;
+        } else {
+            $iscollapsed = 'li';
+        }
+
+        // First check root nodes.
+        $xpath  = "//ul{$hasblocktree}/$hascollapsed/p{$isbranch}/span{$match}|";
+        // Next search for the node containing the text within a link.
+        $xpath .= "//ul{$hasblocktree}//{$notcollapsed}/ul/{$iscollapsed}/p{$isbranch}/a{$match}|";
+        // Finally search for the node containing the text within a span.
+        $xpath .= "//ul{$hasblocktree}//{$notcollapsed}/ul/{$iscollapsed}/p{$isbranch}/span{$match}";
+
+        $node = $this->find('xpath', $xpath, $exception);
+        $this->ensure_node_is_visible($node);
+        return $node;
+    }
+
+    /**
+     * Returns true if the navigation node with the given text is expandable.
+     *
+     * @Given /^navigation node "([^"]*)" should be expandable$/
+     *
+     * @throws ExpectationException
+     * @param string $nodetext
+     * @return bool
+     */
+    public function navigation_node_should_be_expandable($nodetext) {
+        if (!$this->running_javascript()) {
+            // Nodes are only expandable when JavaScript is enabled.
+            return false;
+        }
+
+        $node = $this->get_node_text_node($nodetext, true);
+        $node = $node->getParent();
+        if ($node->hasAttribute('data-expandable') && $node->getAttribute('data-expandable')) {
+            return true;
+        }
+        throw new ExpectationException('The "' . $nodetext . '" node is not expandable', $this->getSession());
+    }
+
+    /**
+     * Returns true if the navigation node with the given text is not expandable.
+     *
+     * @Given /^navigation node "([^"]*)" should not be expandable$/
+     *
+     * @throws ExpectationException
+     * @param string $nodetext
+     * @return bool
+     */
+    public function navigation_node_should_not_be_expandable($nodetext) {
+        if (!$this->running_javascript()) {
+            // Nodes are only expandable when JavaScript is enabled.
+            return false;
+        }
+
+        $node = $this->get_node_text_node($nodetext);
+        $node = $node->getParent();
+        if ($node->hasAttribute('data-expandable') && $node->getAttribute('data-expandable')) {
+            throw new ExpectationException('The "' . $nodetext . '" node is expandable', $this->getSession());
+        }
+        return true;
+    }
+
     /**
      * Expands the selected node of the navigation tree that matches the text.
      * @Given /^I expand "(?P<nodetext_string>(?:[^"]|\\")*)" node$/
      *
      * @throws ExpectationException
      * @param string $nodetext
+     * @return bool|void
      */
     public function i_expand_node($nodetext) {
 
@@ -60,23 +156,12 @@ class behat_navigation extends behat_base {
             return true;
         }
 
-        // Avoid problems with quotes.
-        $nodetextliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($nodetext);
-
-        $xpath = "//ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
-            "/child::li[contains(concat(' ', normalize-space(@class), ' '), ' collapsed ')]" .
-            "/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
-            "/child::span[normalize-space(.)=$nodetextliteral]" .
-            "|" .
-            "//ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
-            "/descendant::li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed '))]" .
-            "/descendant::li[contains(concat(' ', normalize-space(@class), ' '), ' collapsed ')]" .
-            "/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
-            "/child::span[normalize-space(.)=$nodetextliteral]";
-
-        $exception = new ExpectationException('The "' . $nodetext . '" node can not be expanded', $this->getSession());
-        $node = $this->find('xpath', $xpath, $exception);
-        $this->ensure_node_is_visible($node);
+        $node = $this->get_node_text_node($nodetext, true, true, 'The "' . $nodetext . '" node can not be expanded');
+        // Check if the node is a link AND a branch.
+        if (strtolower($node->getTagName()) === 'a') {
+            // We just want to expand the node, we don't want to follow it.
+            $node = $node->getParent();
+        }
         $node->click();
     }
 
@@ -86,6 +171,7 @@ class behat_navigation extends behat_base {
      * @Given /^I collapse "(?P<nodetext_string>(?:[^"]|\\")*)" node$/
      * @throws ExpectationException
      * @param string $nodetext
+     * @return bool|void
      */
     public function i_collapse_node($nodetext) {
 
@@ -94,21 +180,12 @@ class behat_navigation extends behat_base {
             return true;
         }
 
-        // Avoid problems with quotes.
-        $nodetextliteral = $this->getSession()->getSelectorsHandler()->xpathLiteral($nodetext);
-
-        $xpath = "//ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
-            "/child::li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed '))]" .
-            "/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
-            "/child::span[normalize-space(.)=$nodetextliteral]" .
-            "|" .
-            "//ul[contains(concat(' ', normalize-space(@class), ' '), ' block_tree ')]" .
-            "/descendant::li[not(contains(concat(' ', normalize-space(@class), ' '), ' collapsed '))]" .
-            "/child::p[contains(concat(' ', normalize-space(@class), ' '), ' branch ')]" .
-            "/child::span[normalize-space(.)=$nodetextliteral]";
-
-        $exception = new ExpectationException('The "' . $nodetext . '" node can not be collapsed', $this->getSession());
-        $node = $this->find('xpath', $xpath, $exception);
+        $node = $this->get_node_text_node($nodetext, true, false, 'The "' . $nodetext . '" node can not be collapsed');
+        // Check if the node is a link AND a branch.
+        if (strtolower($node->getTagName()) === 'a') {
+            // We just want to expand the node, we don't want to follow it.
+            $node = $node->getParent();
+        }
         $node->click();
     }
 
index c9eb572..2595117 100644 (file)
@@ -41,73 +41,74 @@ class cronlib_testcase extends basic_testcase {
         $tmpdir = realpath($CFG->tempdir);
         $time = time();
 
-        $weekstime = $time - strtotime('1 week');
-        $beforeweekstime = $time - strtotime('1 week') - 1;
-        $afterweekstime = $time + strtotime('1 week') + 1;
-
-        $node1 = new stdClass();
-        $node1->path = '/dir1/dir1_1/dir1_2/dir1_3/';
-        $node1->time = 1;
-        $node1->isdir = true;
-
-        $node2 = new stdClass();
-        $node2->path = '/dir1/dir1_4/';
-        $node2->time = $time;
-        $node2->isdir = true;
-
-        $node3 = new stdClass();
-        $node3->path = '/dir2/';
-        $node3->isdir = true;
-        $node3->time = $time - $weekstime;
-
-        $node4 = new stdClass();
-        $node4->path = '/dir3/';
-        $node4->isdir = true;
-        $node4->time = $time - $afterweekstime;
-
-        $node5 = new stdClass();
-        $node5->path = '/dir1/dir1_1/dir1_2/file1';
-        $node5->isdir = false;
-        $node5->time = $beforeweekstime;
-
-        $node6 = new stdClass();
-        $node6->path = '/dir1/dir1_1/dir1_2/file2';
-        $node6->isdir = false;
-        $node6->time = $time;
-
-        $node7 = new stdClass();
-        $node7->path = '/dir1/dir1_4/file1';
-        $node7->isdir = false;
-        $node7->time = $time - $afterweekstime;
-
-        $node8 = new stdClass();
-        $node8->path = '/dir1/dir1_4/file2';
-        $node8->isdir = false;
-        $node8->time = $time;
-
-        $node9 = new stdClass();
-        $node9->path = '/file1';
-        $node9->isdir = false;
-        $node9->time = $time;
-
-        $node10 = new stdClass();
-        $node10->path = '/file2';
-        $node10->isdir = false;
-        $node10->time = $time - $afterweekstime;
+        $lastweekstime = strtotime('-1 week');
+        $beforelastweekstime = $lastweekstime - 60;
+        $afterlastweekstime = $lastweekstime + 60;
+
+        $nodes = array();
+        // Really old directory to remove.
+        $node[] = $this->generate_test_path('/dir1/dir1_1/dir1_1_1/dir1_1_1_1/', true, 1, false);
+
+        // New Directory to keep.
+        $node[] = $this->generate_test_path('/dir1/dir1_2/', true, $time, true);
+
+        // Directory exactly 1 week old, keep.
+        $node[] = $this->generate_test_path('/dir2/', true, $lastweekstime, true);
+
+        // Directory older than 1 week old, remove.
+        $node[] = $this->generate_test_path('/dir3/', true, $beforelastweekstime, false);
+
+        // File older than 1 week old, remove.
+        $node[] = $this->generate_test_path('/dir1/dir1_1/dir1_1_1/file1_1_1_1', false, $beforelastweekstime, false);
+
+        // New File to keep.
+        $node[] = $this->generate_test_path('/dir1/dir1_1/dir1_1_1/file1_1_1_2', false, $time, true);
+
+        // File older than 1 week old, remove.
+        $node[] = $this->generate_test_path('/dir1/dir1_2/file1_1_2_1', false, $beforelastweekstime, false);
+
+        // New file to keep.
+        $node[] = $this->generate_test_path('/dir1/dir1_2/file1_1_2_2', false, $time, true);
+
+        // New file to keep.
+        $node[] = $this->generate_test_path('/file1', false, $time, true);
+
+        // File older than 1 week, keep.
+        $node[] = $this->generate_test_path('/file2', false, $beforelastweekstime, false);
+
+        // Directory older than 1 week to keep.
+        // Note: Since this directory contains a directory that contains a file that is also older than a week
+        // the directory won't be deleted since it's mtime will be updated when the file is deleted.
+
+        $node[] = $this->generate_test_path('/dir4/dir4_1', true, $beforelastweekstime, true);
+
+        $node[] = $this->generate_test_path('/dir4/dir4_1/dir4_1_1/', true, $beforelastweekstime, true);
+
+        // File older than 1 week to remove.
+        $node[] = $this->generate_test_path('/dir4/dir4_1/dir4_1_1/file4_1_1_1', false, $beforelastweekstime, false);
+
+        $expectednodes = array();
+        foreach ($nodes as $node) {
+            if ($node->keep) {
+                $path = $tmpdir;
+                $pelements = preg_split('/\//', $node->path);
+                foreach ($pelements as $pelement) {
+                    if ($pelement === '') {
+                        continue;
+                    }
+                    $path .= DIRECTORY_SEPARATOR . $pelement;
+                    if (!in_array($path, $expectednodes)) {
+                        $expectednodes[] = $path;
+                    }
+                }
+            }
+        }
+        sort($expectednodes);
 
         $data = array(
                 array(
-                    array($node1, $node2, $node3, $node4, $node5, $node6, $node7, $node8, $node9, $node10),
-                    array(
-                        $tmpdir.DIRECTORY_SEPARATOR.'dir1',
-                        $tmpdir.DIRECTORY_SEPARATOR.'dir1'.DIRECTORY_SEPARATOR.'dir1_1',
-                        $tmpdir.DIRECTORY_SEPARATOR.'dir1'.DIRECTORY_SEPARATOR.'dir1_1'.DIRECTORY_SEPARATOR.'dir1_2',
-                        $tmpdir.DIRECTORY_SEPARATOR.'dir1'.DIRECTORY_SEPARATOR.'dir1_1'.DIRECTORY_SEPARATOR.'dir1_2'.DIRECTORY_SEPARATOR.'file2',
-                        $tmpdir.DIRECTORY_SEPARATOR.'dir1'.DIRECTORY_SEPARATOR.'dir1_4',
-                        $tmpdir.DIRECTORY_SEPARATOR.'dir1'.DIRECTORY_SEPARATOR.'dir1_4'.DIRECTORY_SEPARATOR.'file2',
-                        $tmpdir.DIRECTORY_SEPARATOR.'dir2',
-                        $tmpdir.DIRECTORY_SEPARATOR.'file1',
-                    )
+                    $nodes,
+                    $expectednodes
                 ),
                 array(
                     array(),
@@ -118,6 +119,22 @@ class cronlib_testcase extends basic_testcase {
         return $data;
     }
 
+    /**
+     * Function to populate node array.
+     *
+     * @param string $path Path of directory or file
+     * @param bool $isdir Is the node a directory
+     * @param int $time modified time of the node in epoch
+     * @param bool $keep Should the node exist after the delete function has run
+     */
+    private function generate_test_path($path, $isdir = false, $time = 0, $keep = false) {
+        $node = new stdClass();
+        $node->path = $path;
+        $node->isdir = $isdir;
+        $node->time = $time;
+        $node->keep = $keep;
+        return $node;
+    }
     /**
      * Test removing files and directories from tempdir.
      *
@@ -136,6 +153,13 @@ class cronlib_testcase extends basic_testcase {
             }
             touch($tmpdir.$data->path, $data->time);
         }
+        // We need to iterate through again since adding a file to a directory will
+        // update the modified time of the directory.
+        foreach ($nodes as $data) {
+            if ($data->isdir) {
+                touch($tmpdir.$data->path, $data->time);
+            }
+        }
 
         $task = new \core\task\file_temp_cleanup_task();
         $task->execute();
index 8ba3a26..5a9f02c 100644 (file)
@@ -1176,6 +1176,12 @@ CSS;
         $this->assertCount(1, $chunks);
         $this->assertSame('@media (min-width: 980px) { .a,.b{} }', $chunks[0]);
 
+        // Test media queries, with commas.
+        $css = '.a{} @media (min-width: 700px), handheld and (orientation: landscape) { .b{} }';
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
+        $this->assertCount(1, $chunks);
+        $this->assertSame($css, $chunks[0]);
+
         // Test special rules.
         $css = 'a,b{ background-image: linear-gradient(to bottom, #ffffff, #cccccc);}d,e{}';
         $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
@@ -1229,6 +1235,23 @@ CSS;
         $this->assertCount(2, $chunks);
         $this->assertSame('a,b{}', $chunks[0]);
         $this->assertSame("@import url(styles.php?type=test&chunk=1);\n nav a:hover:after { content: \"↓\"; } b{ color:test;}", $chunks[1]);
+
+        // Test that if there is broken CSS with too many close brace symbols,
+        // media rules after that point are still kept together.
+        $mediarule = '@media (width=480) {a{}b{}}';
+        $css = 'c{}}' . $mediarule . 'd{}';
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
+        $this->assertCount(3, $chunks);
+        $this->assertEquals($mediarule, $chunks[1]);
+
+        // Test that this still works even with too many close brace symbols
+        // inside a media query (note: that broken media query may be split
+        // after the break, but any following ones should not be).
+        $brokenmediarule = '@media (width=480) {c{}}d{}}';
+        $css = $brokenmediarule . 'e{}' . $mediarule . 'f{}';
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
+        $this->assertCount(4, $chunks);
+        $this->assertEquals($mediarule, $chunks[2]);
     }
 
     /**
index 18f1493..3830bda 100644 (file)
@@ -2547,6 +2547,18 @@ class core_moodlelib_testcase extends advanced_testcase {
 
         email_to_user($user1, $user2, $subject, $messagetext);
         $this->assertDebuggingCalled('Unit tests must not send real emails! Use $this->redirectEmails()');
+
+        // Test $CFG->emailonlyfromnoreplyaddress.
+        set_config('emailonlyfromnoreplyaddress', 1);
+        $this->assertNotEmpty($CFG->emailonlyfromnoreplyaddress);
+        $sink = $this->redirectEmails();
+        email_to_user($user1, $user2, $subject, $messagetext);
+        unset_config('emailonlyfromnoreplyaddress');
+        email_to_user($user1, $user2, $subject, $messagetext);
+        $result = $sink->get_messages();
+        $this->assertEquals($CFG->noreplyaddress, $result[0]->from);
+        $this->assertNotEquals($CFG->noreplyaddress, $result[1]->from);
+        $sink->close();
     }
 
     /**
index 01e48c1..03d307f 100644 (file)
@@ -1999,7 +1999,7 @@ function upgrade_save_orphaned_questions() {
  * @see backup_cron_automated_helper::remove_excess_backups()
  * @link http://tracker.moodle.org/browse/MDL-35116
  * @return void
- * @since 2.4
+ * @since Moodle 2.4
  */
 function upgrade_rename_old_backup_files_using_shortname() {
     global $CFG;
index 6bb45d0..e6b0b7f 100644 (file)
@@ -973,7 +973,7 @@ function page_doc_link($text='') {
 /**
  * Returns the path to use when constructing a link to the docs.
  *
- * @since 2.5.1 2.6
+ * @since Moodle 2.5.1 2.6
  * @param moodle_page $page
  * @return string
  */
index 44c9cb0..cc265b3 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception-debug.js and b/lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception-debug.js differ
index 972d845..dbe7855 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception-min.js and b/lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception-min.js differ
index 44c9cb0..cc265b3 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception.js and b/lib/yui/build/moodle-core-notification-ajaxexception/moodle-core-notification-ajaxexception.js differ
index d3da176..6348d4d 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-confirm/moodle-core-notification-confirm-debug.js and b/lib/yui/build/moodle-core-notification-confirm/moodle-core-notification-confirm-debug.js differ
index 13d960e..3d45e82 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-confirm/moodle-core-notification-confirm-min.js and b/lib/yui/build/moodle-core-notification-confirm/moodle-core-notification-confirm-min.js differ
index d3da176..6348d4d 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-confirm/moodle-core-notification-confirm.js and b/lib/yui/build/moodle-core-notification-confirm/moodle-core-notification-confirm.js differ
index 1ab384e..c8da6ee 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-debug.js and b/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-debug.js differ
index f67b779..65762d5 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-min.js and b/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-min.js differ
index b3898af..8387c3f 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue.js and b/lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue.js differ
index 9ca3e81..968109c 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-debug.js and b/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-debug.js differ
index ba222b3..2007b8f 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-min.js and b/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception-min.js differ
index 9ca3e81..968109c 100644 (file)
Binary files a/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception.js and b/lib/yui/build/moodle-core-notification-exception/moodle-core-notification-exception.js differ
index f364995..74eb5dc 100644 (file)
@@ -73,7 +73,7 @@ Y.extend(AJAXEXCEPTION, M.core.notification.info, {
          */
         error : {
             validator : Y.Lang.isString,
-            value : 'Unknown error'
+            value: M.util.get_string('unknownerror', 'moodle')
         },
 
         /**
index 6cc6f94..d2e640b 100644 (file)
@@ -84,7 +84,7 @@ Y.extend(CONFIRM, M.core.notification.info, {
          */
         yesLabel: {
             validator: Y.Lang.isString,
-            value: 'Yes'
+            value: M.util.get_string('yes', 'moodle')
         },
 
         /**
@@ -96,7 +96,7 @@ Y.extend(CONFIRM, M.core.notification.info, {
          */
         noLabel: {
             validator: Y.Lang.isString,
-            value: 'No'
+            value: M.util.get_string('no', 'moodle')
         },
 
         /**
@@ -108,7 +108,7 @@ Y.extend(CONFIRM, M.core.notification.info, {
          */
         title: {
             validator: Y.Lang.isString,
-            value: 'Confirm'
+            value: M.util.get_string('confirm', 'moodle')
         },
 
         /**
@@ -120,7 +120,7 @@ Y.extend(CONFIRM, M.core.notification.info, {
          */
         question: {
             validator: Y.Lang.isString,
-            value: 'Are you sure?'
+            value: M.util.get_string('areyousure', 'moodle')
         }
     }
 });
index 4910212..0a9320b 100644 (file)
@@ -420,7 +420,7 @@ Y.extend(DIALOGUE, Y.Panel, {
          */
         closeButtonTitle : {
             validator : Y.Lang.isString,
-            value : 'Close'
+            value: M.util.get_string('closebuttontitle', 'moodle')
         },
 
         /**
index 482b861..78186ea 100644 (file)
@@ -17,9 +17,24 @@ var EXCEPTION_NAME = 'Moodle exception',
  * @class M.core.exception
  * @extends M.core.dialogue
  */
-EXCEPTION = function(config) {
+EXCEPTION = function(c) {
+    var config = Y.mix({}, c);
     config.width = config.width || (M.cfg.developerdebug)?Math.floor(Y.one(document.body).get('winWidth')/3)+'px':null;
     config.closeButton = true;
+
+    // We need to whitelist some properties which are part of the exception
+    // prototype, otherwise AttributeCore filters them during value normalisation.
+    var whitelist = [
+        'message',
+        'name',
+        'fileName',
+        'lineNumber',
+        'stack'
+    ];
+    Y.Array.each(whitelist, function(k) {
+        config[k] = c[k];
+    });
+
     EXCEPTION.superclass.constructor.apply(this, [config]);
 };
 Y.extend(EXCEPTION, M.core.notification.info, {
index c42df23..1ea4932 100644 (file)
@@ -189,7 +189,7 @@ class core_message_external extends external_api {
      * Create contacts parameters description.
      *
      * @return external_function_parameters
-     * @since 2.5
+     * @since Moodle 2.5
      */
     public static function create_contacts_parameters() {
         return new external_function_parameters(
@@ -207,7 +207,7 @@ class core_message_external extends external_api {
      *
      * @param array $userids array of user IDs.
      * @return external_description
-     * @since 2.5
+     * @since Moodle 2.5
      */
     public static function create_contacts($userids) {
         $params = array('userids' => $userids);
@@ -231,7 +231,7 @@ class core_message_external extends external_api {
      * Create contacts return description.
      *
      * @return external_description
-     * @since 2.5
+     * @since Moodle 2.5
      */
     public static function create_contacts_returns() {
         return new external_warnings();
@@ -241,7 +241,7 @@ class core_message_external extends external_api {
      * Delete contacts parameters description.
      *
      * @return external_function_parameters
-     * @since 2.5
+     * @since Moodle 2.5
      */
     public static function delete_contacts_parameters() {
         return new external_function_parameters(
@@ -259,7 +259,7 @@ class core_message_external extends external_api {
      *
      * @param array $userids array of user IDs.
      * @return null
-     * @since 2.5
+     * @since Moodle 2.5
      */
     public static function delete_contacts($userids) {
         $params = array('userids' => $userids);
@@ -276,7 +276,7 @@ class core_message_external extends external_api {
      * Delete contacts return description.
      *
      * @return external_description
-     * @since 2.5
+     * @since Moodle 2.5
      */
     public static function delete_contacts_returns() {
         return null;
@@ -286,7