Merge branch 'MDL-45089_chat' of https://github.com/andyjdavis/moodle
authorDan Poltawski <dan@moodle.com>
Wed, 16 Apr 2014 05:00:46 +0000 (13:00 +0800)
committerDan Poltawski <dan@moodle.com>
Wed, 16 Apr 2014 05:00:46 +0000 (13:00 +0800)
368 files changed:
admin/tool/log/db/install.php
admin/tool/log/db/upgrade.php [new file with mode: 0644]
admin/tool/log/store/legacy/classes/event/legacy_logged.php
admin/tool/log/store/legacy/settings.php
admin/tool/log/store/standard/db/install.xml
admin/tool/log/store/standard/db/upgrade.php
admin/tool/log/store/standard/version.php
admin/tool/log/version.php
blocks/comments/classes/event/comment_created.php
blocks/comments/classes/event/comment_deleted.php
blocks/navigation/block_navigation.php
blocks/recent_activity/block_recent_activity.php
filter/glossary/filter.php
filter/glossary/tests/filter_test.php
filter/glossary/version.php
filter/tex/filter.php
filter/tex/tests/filter_test.php [new file with mode: 0644]
lang/en/moodle.php
lib/accesslib.php
lib/classes/event/assessable_submitted.php
lib/classes/event/assessable_uploaded.php
lib/classes/event/base.php
lib/classes/event/blog_association_created.php
lib/classes/event/blog_comment_created.php
lib/classes/event/blog_comment_deleted.php
lib/classes/event/blog_entries_viewed.php
lib/classes/event/blog_entry_created.php
lib/classes/event/blog_entry_deleted.php
lib/classes/event/blog_entry_updated.php
lib/classes/event/calendar_event_created.php
lib/classes/event/calendar_event_deleted.php
lib/classes/event/calendar_event_updated.php
lib/classes/event/cohort_created.php
lib/classes/event/cohort_deleted.php
lib/classes/event/cohort_member_added.php
lib/classes/event/cohort_member_removed.php
lib/classes/event/cohort_updated.php
lib/classes/event/comment_created.php
lib/classes/event/comment_deleted.php
lib/classes/event/comments_viewed.php
lib/classes/event/content_viewed.php
lib/classes/event/course_category_created.php
lib/classes/event/course_category_deleted.php
lib/classes/event/course_category_updated.php
lib/classes/event/course_completed.php
lib/classes/event/course_completion_updated.php
lib/classes/event/course_content_deleted.php
lib/classes/event/course_created.php
lib/classes/event/course_deleted.php
lib/classes/event/course_module_completion_updated.php
lib/classes/event/course_module_created.php
lib/classes/event/course_module_deleted.php
lib/classes/event/course_module_instance_list_viewed.php
lib/classes/event/course_module_instances_list_viewed.php
lib/classes/event/course_module_updated.php
lib/classes/event/course_module_viewed.php
lib/classes/event/course_reset_ended.php
lib/classes/event/course_reset_started.php
lib/classes/event/course_resources_list_viewed.php
lib/classes/event/course_restored.php
lib/classes/event/course_section_updated.php
lib/classes/event/course_updated.php
lib/classes/event/email_failed.php
lib/classes/event/group_created.php
lib/classes/event/group_deleted.php
lib/classes/event/group_member_added.php
lib/classes/event/group_member_removed.php
lib/classes/event/group_updated.php
lib/classes/event/grouping_created.php
lib/classes/event/grouping_deleted.php
lib/classes/event/grouping_updated.php
lib/classes/event/item_tagged.php
lib/classes/event/item_untagged.php
lib/classes/event/manager.php
lib/classes/event/message_contact_added.php
lib/classes/event/message_contact_blocked.php
lib/classes/event/message_contact_removed.php
lib/classes/event/message_contact_unblocked.php
lib/classes/event/message_read.php
lib/classes/event/message_sent.php
lib/classes/event/mnet_access_control_created.php
lib/classes/event/mnet_access_control_updated.php
lib/classes/event/note_created.php
lib/classes/event/note_deleted.php
lib/classes/event/note_updated.php
lib/classes/event/notes_viewed.php
lib/classes/event/role_allow_assign_updated.php
lib/classes/event/role_allow_override_updated.php
lib/classes/event/role_allow_switch_updated.php
lib/classes/event/role_assigned.php
lib/classes/event/role_capabilities_updated.php
lib/classes/event/role_deleted.php
lib/classes/event/role_unassigned.php
lib/classes/event/tag_created.php
lib/classes/event/tag_deleted.php
lib/classes/event/tag_flagged.php
lib/classes/event/tag_unflagged.php
lib/classes/event/tag_updated.php
lib/classes/event/unknown_logged.php [new file with mode: 0644]
lib/classes/event/user_created.php
lib/classes/event/user_deleted.php
lib/classes/event/user_enrolment_created.php
lib/classes/event/user_enrolment_deleted.php
lib/classes/event/user_enrolment_updated.php
lib/classes/event/user_graded.php
lib/classes/event/user_list_viewed.php
lib/classes/event/user_loggedin.php
lib/classes/event/user_loggedinas.php
lib/classes/event/user_loggedout.php
lib/classes/event/user_login_failed.php
lib/classes/event/user_profile_viewed.php
lib/classes/event/user_updated.php
lib/classes/event/webservice_function_called.php
lib/classes/event/webservice_login_failed.php
lib/classes/event/webservice_service_created.php
lib/classes/event/webservice_service_deleted.php
lib/classes/event/webservice_service_updated.php
lib/classes/event/webservice_service_user_added.php
lib/classes/event/webservice_service_user_removed.php
lib/classes/event/webservice_token_created.php
lib/classes/event/webservice_token_sent.php
lib/classes/grades_external.php
lib/csslib.php
lib/deprecatedlib.php
lib/dml/mariadb_native_moodle_database.php
lib/editor/atto/plugins/image/lang/en/atto_image.php
lib/editor/atto/plugins/image/lib.php
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/styles.css
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/editor-plugin-buttons.js
lib/filestorage/stored_file.php
lib/moodlelib.php
lib/pagelib.php
lib/setuplib.php
lib/tests/csslib_test.php
lib/tests/event_unknown_logged_test.php [new file with mode: 0644]
lib/tests/eventslib_test.php
lib/tests/grades_externallib_test.php
lib/tests/moodlelib_test.php
lib/upgradelib.php
mod/assign/classes/event/all_submissions_downloaded.php
mod/assign/classes/event/assessable_submitted.php
mod/assign/classes/event/extension_granted.php
mod/assign/classes/event/identities_revealed.php
mod/assign/classes/event/marker_updated.php
mod/assign/classes/event/statement_accepted.php
mod/assign/classes/event/submission_created.php
mod/assign/classes/event/submission_duplicated.php
mod/assign/classes/event/submission_graded.php
mod/assign/classes/event/submission_locked.php
mod/assign/classes/event/submission_status_updated.php
mod/assign/classes/event/submission_unlocked.php
mod/assign/classes/event/submission_updated.php
mod/assign/classes/event/workflow_state_updated.php
mod/assign/lib.php
mod/assign/submission/comments/classes/event/comment_created.php
mod/assign/submission/comments/classes/event/comment_deleted.php
mod/assign/submission/file/classes/event/assessable_uploaded.php
mod/assign/submission/file/classes/event/submission_created.php
mod/assign/submission/file/classes/event/submission_updated.php
mod/assign/submission/onlinetext/classes/event/assessable_uploaded.php
mod/assign/submission/onlinetext/classes/event/submission_created.php
mod/assign/submission/onlinetext/classes/event/submission_updated.php
mod/book/classes/event/chapter_created.php
mod/book/classes/event/chapter_deleted.php
mod/book/classes/event/chapter_updated.php
mod/book/classes/event/chapter_viewed.php
mod/book/classes/event/course_module_instance_list_viewed.php
mod/book/classes/event/course_module_viewed.php
mod/book/lib.php
mod/book/tool/exportimscp/classes/event/book_exported.php
mod/book/tool/print/classes/event/book_printed.php
mod/book/tool/print/classes/event/chapter_printed.php
mod/book/tool/print/lib.php
mod/chat/classes/event/course_module_instance_list_viewed.php
mod/chat/classes/event/message_sent.php
mod/chat/classes/event/sessions_viewed.php
mod/chat/lib.php
mod/choice/classes/event/answer_submitted.php
mod/choice/classes/event/answer_updated.php
mod/choice/classes/event/course_module_instance_list_viewed.php
mod/choice/classes/event/course_module_viewed.php
mod/choice/classes/event/report_viewed.php
mod/choice/lib.php
mod/data/classes/event/comment_created.php
mod/data/classes/event/comment_deleted.php
mod/data/classes/event/course_module_instance_list_viewed.php
mod/data/classes/event/course_module_viewed.php
mod/data/classes/event/field_created.php
mod/data/classes/event/field_deleted.php
mod/data/classes/event/field_updated.php
mod/data/classes/event/record_created.php
mod/data/classes/event/record_deleted.php
mod/data/classes/event/record_updated.php
mod/data/classes/event/template_updated.php
mod/data/classes/event/template_viewed.php
mod/data/lib.php
mod/feedback/classes/event/course_module_instance_list_viewed.php
mod/feedback/classes/event/course_module_viewed.php
mod/feedback/classes/event/response_deleted.php
mod/feedback/classes/event/response_submitted.php
mod/feedback/lib.php
mod/folder/classes/event/course_module_instance_list_viewed.php
mod/folder/classes/event/course_module_viewed.php
mod/folder/classes/event/folder_updated.php
mod/folder/lib.php
mod/forum/classes/event/assessable_uploaded.php
mod/forum/classes/event/course_module_instance_list_viewed.php
mod/forum/classes/event/course_module_viewed.php
mod/forum/classes/event/course_searched.php
mod/forum/classes/event/discussion_created.php
mod/forum/classes/event/discussion_deleted.php
mod/forum/classes/event/discussion_moved.php
mod/forum/classes/event/discussion_updated.php
mod/forum/classes/event/discussion_viewed.php
mod/forum/classes/event/post_created.php
mod/forum/classes/event/post_deleted.php
mod/forum/classes/event/post_updated.php
mod/forum/classes/event/readtracking_disabled.php
mod/forum/classes/event/readtracking_enabled.php
mod/forum/classes/event/subscribers_viewed.php
mod/forum/classes/event/subscription_created.php
mod/forum/classes/event/subscription_deleted.php
mod/forum/classes/event/userreport_viewed.php
mod/forum/lib.php
mod/glossary/approve.php
mod/glossary/classes/event/category_created.php
mod/glossary/classes/event/category_deleted.php
mod/glossary/classes/event/category_updated.php
mod/glossary/classes/event/comment_created.php
mod/glossary/classes/event/comment_deleted.php
mod/glossary/classes/event/course_module_instance_list_viewed.php
mod/glossary/classes/event/course_module_viewed.php
mod/glossary/classes/event/entry_approved.php
mod/glossary/classes/event/entry_created.php
mod/glossary/classes/event/entry_deleted.php
mod/glossary/classes/event/entry_disapproved.php
mod/glossary/classes/event/entry_updated.php
mod/glossary/classes/event/entry_viewed.php
mod/glossary/classes/local/concept_cache.php [new file with mode: 0644]
mod/glossary/db/caches.php [new file with mode: 0644]
mod/glossary/db/events.php [new file with mode: 0644]
mod/glossary/deleteentry.php
mod/glossary/edit.php
mod/glossary/editcategories.php
mod/glossary/import.php
mod/glossary/lang/en/glossary.php
mod/glossary/lib.php
mod/glossary/tests/concept_cache_test.php [new file with mode: 0644]
mod/glossary/tests/generator/lib.php
mod/glossary/tests/generator_test.php
mod/glossary/version.php
mod/imscp/classes/event/course_module_instance_list_viewed.php
mod/imscp/classes/event/course_module_viewed.php
mod/imscp/lib.php
mod/label/lib.php
mod/lesson/classes/event/course_module_instance_list_viewed.php
mod/lesson/classes/event/course_module_viewed.php
mod/lesson/classes/event/essay_assessed.php
mod/lesson/classes/event/essay_attempt_viewed.php
mod/lesson/classes/event/highscore_added.php
mod/lesson/classes/event/highscores_viewed.php
mod/lesson/classes/event/lesson_ended.php
mod/lesson/classes/event/lesson_started.php
mod/lesson/lib.php
mod/lti/classes/event/course_module_instance_list_viewed.php
mod/lti/classes/event/course_module_viewed.php
mod/lti/classes/event/unknown_service_api_called.php
mod/page/classes/event/course_module_instance_list_viewed.php
mod/page/classes/event/course_module_viewed.php
mod/page/lib.php
mod/quiz/classes/event/attempt_abandoned.php
mod/quiz/classes/event/attempt_becameoverdue.php
mod/quiz/classes/event/attempt_started.php
mod/quiz/classes/event/attempt_submitted.php
mod/quiz/lib.php
mod/quiz/overridedelete.php
mod/quiz/overrideedit.php
mod/quiz/tests/events_test.php
mod/resource/classes/event/course_module_instance_list_viewed.php
mod/resource/classes/event/course_module_viewed.php
mod/resource/lib.php
mod/scorm/classes/event/attempt_deleted.php
mod/scorm/classes/event/course_module_instance_list_viewed.php
mod/scorm/classes/event/course_module_viewed.php
mod/scorm/classes/event/interactions_viewed.php
mod/scorm/classes/event/report_viewed.php
mod/scorm/classes/event/sco_launched.php
mod/scorm/classes/event/tracks_viewed.php
mod/scorm/classes/event/user_report_viewed.php
mod/scorm/lib.php
mod/survey/classes/event/course_module_instance_list_viewed.php
mod/survey/classes/event/course_module_viewed.php
mod/survey/classes/event/report_downloaded.php
mod/survey/classes/event/report_viewed.php
mod/survey/classes/event/response_submitted.php
mod/survey/lib.php
mod/upgrade.txt
mod/url/classes/event/course_module_instance_list_viewed.php
mod/url/classes/event/course_module_viewed.php
mod/url/lib.php
mod/wiki/classes/event/comment_created.php
mod/wiki/classes/event/comment_deleted.php
mod/wiki/classes/event/comments_viewed.php
mod/wiki/classes/event/course_module_instance_list_viewed.php
mod/wiki/classes/event/course_module_viewed.php
mod/wiki/classes/event/page_created.php
mod/wiki/classes/event/page_deleted.php
mod/wiki/classes/event/page_diff_viewed.php
mod/wiki/classes/event/page_history_viewed.php
mod/wiki/classes/event/page_locks_deleted.php
mod/wiki/classes/event/page_map_viewed.php
mod/wiki/classes/event/page_updated.php
mod/wiki/classes/event/page_version_deleted.php
mod/wiki/classes/event/page_version_restored.php
mod/wiki/classes/event/page_version_viewed.php
mod/wiki/classes/event/page_viewed.php
mod/workshop/classes/event/assessable_uploaded.php
mod/workshop/classes/event/assessment_evaluated.php
mod/workshop/classes/event/assessment_evaluations_reset.php
mod/workshop/classes/event/assessment_reevaluated.php
mod/workshop/classes/event/assessments_reset.php
mod/workshop/classes/event/course_module_instance_list_viewed.php
mod/workshop/classes/event/course_module_viewed.php
mod/workshop/classes/event/phase_switched.php
mod/workshop/classes/event/submission_assessed.php
mod/workshop/classes/event/submission_created.php
mod/workshop/classes/event/submission_reassessed.php
mod/workshop/classes/event/submission_updated.php
mod/workshop/classes/event/submission_viewed.php
question/type/numerical/question.php
question/type/numerical/tests/question_test.php
report/completion/classes/event/report_viewed.php
report/completion/classes/event/user_report_viewed.php
report/log/classes/event/report_viewed.php
report/log/classes/event/user_report_viewed.php
report/log/graph.php
report/log/locallib.php
report/log/tests/behat/filter_log.feature
report/log/tests/behat/user_log.feature
report/log/user.php
report/loglive/classes/event/report_viewed.php
report/loglive/classes/table_log.php
report/loglive/tests/behat/loglive_report.feature
report/outline/classes/event/activity_viewed.php
report/outline/classes/event/outline_viewed.php
report/participation/classes/event/report_viewed.php
report/participation/index.php
report/participation/lang/en/report_participation.php
report/participation/locallib.php [new file with mode: 0644]
report/participation/tests/behat/filter_paticipation.feature [new file with mode: 0644]
report/stats/classes/event/report_viewed.php
report/stats/classes/event/user_report_viewed.php
repository/wikimedia/lib.php
tag/manage.php
theme/bootstrapbase/less/moodle/core.less
theme/bootstrapbase/less/moodle/responsive.less
theme/bootstrapbase/less/moodle/user.less
theme/bootstrapbase/style/moodle.css
theme/styles.php
version.php

index 6fccec4..52d2d9d 100644 (file)
 
 defined('MOODLE_INTERNAL') || die();
 
+/**
+ * Install the plugin.
+ */
 function xmldb_tool_log_install() {
-    global $CFG;
+    global $CFG, $DB;
 
     $enabled = array();
 
-    // For now enable only the legacy logging, this keeps 100% BC.
+    // Add data to new log only from now on.
+    if (file_exists("$CFG->dirroot/$CFG->admin/tool/log/store/standard")) {
+        $enabled[] = 'logstore_standard';
+    }
+
+    // Enable legacy log reading, but only if there are existing data.
     if (file_exists("$CFG->dirroot/$CFG->admin/tool/log/store/legacy")) {
-        $enabled[] = 'logstore_legacy';
+        unset_config('loglegacy', 'logstore_legacy');
+        // Do not enabled legacy logging if somebody installed a new
+        // site and in less than one day upgraded to 2.7.
+        $params = array('yesterday' => time() - 60*60*24);
+        if ($DB->record_exists_select('log', "time < :yesterday", $params)) {
+            $enabled[] = 'logstore_legacy';
+        }
     }
 
     set_config('enabled_stores', implode(',', $enabled), 'tool_log');
diff --git a/admin/tool/log/db/upgrade.php b/admin/tool/log/db/upgrade.php
new file mode 100644 (file)
index 0000000..0dc0597
--- /dev/null
@@ -0,0 +1,47 @@
+<?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/>.
+
+/**
+ * Logging support.
+ *
+ * @package    tool_log
+ * @copyright  2014 Petr Skoda {@link http://skodak.org}
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Upgrade the plugin.
+ *
+ * @param int $oldversion
+ * @return bool always true
+ */
+function xmldb_tool_log_upgrade($oldversion) {
+    global $CFG, $DB, $OUTPUT;
+
+    $dbman = $DB->get_manager();
+
+    if ($oldversion < 2014040600) {
+        // Reset logging defaults in dev branches,
+        // in production upgrade the install.php is executed instead.
+        require_once(__DIR__ . '/install.php');
+        xmldb_tool_log_install();
+        upgrade_plugin_savepoint(true, 2014040600, 'tool', 'log');
+    }
+
+    return true;
+}
index 198e27a..f485cca 100644 (file)
@@ -22,6 +22,7 @@ defined('MOODLE_INTERNAL') || die();
  * Legacy log emulation event class.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2013 Petr Skoda {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index d9ed97b..0a7149e 100644 (file)
@@ -27,7 +27,7 @@ defined('MOODLE_INTERNAL') || die();
 if ($hassiteconfig) {
     $settings->add(new admin_setting_configcheckbox('logstore_legacy/loglegacy',
         new lang_string('loglegacy', 'logstore_legacy'),
-        new lang_string('loglegacy_help', 'logstore_legacy'), 1));
+        new lang_string('loglegacy_help', 'logstore_legacy'), 0));
 
     $settings->add(new admin_setting_configcheckbox('logguests',
         new lang_string('logguests', 'admin'),
index 053f8cd..9586c03 100644 (file)
@@ -1,5 +1,5 @@
 <?xml version="1.0" encoding="UTF-8" ?>
-<XMLDB PATH="admin/tool/log/store/standard/db" VERSION="20140320" COMMENT="XMLDB file for Moodle admin/tool/log/store/standard"
+<XMLDB PATH="admin/tool/log/store/standard/db" VERSION="20140415" COMMENT="XMLDB file for Moodle admin/tool/log/store/standard"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:noNamespaceSchemaLocation="../../../../../../lib/xmldb/xmldb.xsd"
 >
       </KEYS>
       <INDEXES>
         <INDEX NAME="timecreated" UNIQUE="false" FIELDS="timecreated"/>
-        <INDEX NAME="contextid-component" UNIQUE="false" FIELDS="contextid, component"/>
-        <INDEX NAME="courseid" UNIQUE="false" FIELDS="courseid"/>
-        <INDEX NAME="eventname" UNIQUE="false" FIELDS="eventname"/>
-        <INDEX NAME="crud" UNIQUE="false" FIELDS="crud"/>
-        <INDEX NAME="edulevel" UNIQUE="false" FIELDS="edulevel"/>
+        <INDEX NAME="course-time" UNIQUE="false" FIELDS="courseid, anonymous, timecreated"/>
+        <INDEX NAME="user-module" UNIQUE="false" FIELDS="userid, contextlevel, contextinstanceid, crud, edulevel, timecreated"/>
       </INDEXES>
     </TABLE>
   </TABLES>
index db7a122..d394d46 100644 (file)
@@ -42,5 +42,74 @@ function xmldb_logstore_standard_upgrade($oldversion) {
         upgrade_plugin_savepoint(true, 2014032000, 'logstore', 'standard');
     }
 
+    if ($oldversion < 2014041500) {
+
+        // Define index contextid-component (not unique) to be dropped form logstore_standard_log.
+        $table = new xmldb_table('logstore_standard_log');
+        $index = new xmldb_index('contextid-component', XMLDB_INDEX_NOTUNIQUE, array('contextid', 'component'));
+
+        // Conditionally launch drop index contextid-component.
+        if ($dbman->index_exists($table, $index)) {
+            $dbman->drop_index($table, $index);
+        }
+
+        // Define index courseid (not unique) to be dropped form logstore_standard_log.
+        $table = new xmldb_table('logstore_standard_log');
+        $index = new xmldb_index('courseid', XMLDB_INDEX_NOTUNIQUE, array('courseid'));
+
+        // Conditionally launch drop index courseid.
+        if ($dbman->index_exists($table, $index)) {
+            $dbman->drop_index($table, $index);
+        }
+
+        // Define index eventname (not unique) to be dropped form logstore_standard_log.
+        $table = new xmldb_table('logstore_standard_log');
+        $index = new xmldb_index('eventname', XMLDB_INDEX_NOTUNIQUE, array('eventname'));
+
+        // Conditionally launch drop index eventname.
+        if ($dbman->index_exists($table, $index)) {
+            $dbman->drop_index($table, $index);
+        }
+
+        // Define index crud (not unique) to be dropped form logstore_standard_log.
+        $table = new xmldb_table('logstore_standard_log');
+        $index = new xmldb_index('crud', XMLDB_INDEX_NOTUNIQUE, array('crud'));
+
+        // Conditionally launch drop index crud.
+        if ($dbman->index_exists($table, $index)) {
+            $dbman->drop_index($table, $index);
+        }
+
+        // Define index edulevel (not unique) to be dropped form logstore_standard_log.
+        $table = new xmldb_table('logstore_standard_log');
+        $index = new xmldb_index('edulevel', XMLDB_INDEX_NOTUNIQUE, array('edulevel'));
+
+        // Conditionally launch drop index edulevel.
+        if ($dbman->index_exists($table, $index)) {
+            $dbman->drop_index($table, $index);
+        }
+
+        // Define index course-time (not unique) to be added to logstore_standard_log.
+        $table = new xmldb_table('logstore_standard_log');
+        $index = new xmldb_index('course-time', XMLDB_INDEX_NOTUNIQUE, array('courseid', 'anonymous', 'timecreated'));
+
+        // Conditionally launch add index course-time.
+        if (!$dbman->index_exists($table, $index)) {
+            $dbman->add_index($table, $index);
+        }
+
+        // Define index user-module (not unique) to be added to logstore_standard_log.
+        $table = new xmldb_table('logstore_standard_log');
+        $index = new xmldb_index('user-module', XMLDB_INDEX_NOTUNIQUE, array('userid', 'contextlevel', 'contextinstanceid', 'crud', 'edulevel', 'timecreated'));
+
+        // Conditionally launch add index user-module.
+        if (!$dbman->index_exists($table, $index)) {
+            $dbman->add_index($table, $index);
+        }
+
+        // Standard savepoint reached.
+        upgrade_plugin_savepoint(true, 2014041500, 'logstore', 'standard');
+    }
+
     return true;
 }
index 94f88e2..32ba411 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version = 2014032000; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->version = 2014041500; // The current plugin version (Date: YYYYMMDDXX).
 $plugin->requires = 2014031200; // Requires this Moodle version.
 $plugin->component = 'logstore_standard'; // Full name of the plugin (used for diagnostics).
index 0838cd2..a70afc3 100644 (file)
@@ -24,6 +24,6 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version = 2014011300; // The current plugin version (Date: YYYYMMDDXX).
-$plugin->requires = 2014011000; // Requires this Moodle version.
+$plugin->version = 2014040600; // The current plugin version (Date: YYYYMMDDXX).
+$plugin->requires = 2014040300; // Requires this Moodle version.
 $plugin->component = 'tool_log'; // Full name of the plugin (used for diagnostics).
index db96870..5864f83 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * block_comments comment created event.
  *
  * @package    block_comments
+ * @since      Moodle 2.7
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index a347c0b..6e1214d 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * block_comments comment deleted event.
  *
  * @package    block_comments
+ * @since      Moodle 2.7
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 9b2613b..f152729 100644 (file)
@@ -163,7 +163,7 @@ class block_navigation extends block_base {
             redirect($url);
         }
 
-        $trimmode = self::TRIM_LEFT;
+        $trimmode = self::TRIM_RIGHT;
         $trimlength = 50;
 
         if (!empty($this->config->trimmode)) {
index ed3ffcb..ce97602 100644 (file)
@@ -172,7 +172,7 @@ class block_recent_activity extends block_base {
                     $changelist[$log->cmid] = array('action' => 'delete mod',
                         'module' => (object)array(
                             'modname' => $log->modname,
-                            'modfullname' => $modnames[$log->modname]
+                            'modfullname' => isset($modnames[$log->modname]) ? $modnames[$log->modname] : $log->modname
                          ));
 
                 } else if (!$wasdeleted && isset($modinfo->cms[$log->cmid]) && $canviewupdated) {
index a1ddebb..016efd6 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * This filter provides automatic linking to
  * glossary entries, aliases and categories when
- * found inside every Moodle text
+ * found inside every Moodle text.
  *
  * @package    filter
  * @subpackage glossary
 defined('MOODLE_INTERNAL') || die();
 
 /**
- * Glossary filtering
+ * Glossary linking filter class.
  *
- * TODO: erase the $GLOSSARY_EXCLUDECONCEPTS global => require format_text()
- *       to be able to pass arbitrary $options['filteroptions']['glossary'] to filter_text()
+ * NOTE: multilang glossary entries are not compatible with this filter.
  */
 class filter_glossary extends moodle_text_filter {
+    /** @var int $cachecourseid cache invalidation flag in case content from multiple courses displayed. */
+    protected $cachecourseid = null;
+    /** @var int $cacheuserid cache invalidation flag in case user is switched. */
+    protected $cacheuserid = null;
+    /** @var array $cacheconceptlist page level filter cache, this should be always faster than MUC */
+    protected $cacheconceptlist = null;
 
     public function setup($page, $context) {
         // This only requires execution once per request.
@@ -49,185 +54,100 @@ class filter_glossary extends moodle_text_filter {
     }
 
     public function filter($text, array $options = array()) {
-        global $CFG, $DB, $GLOSSARY_EXCLUDECONCEPTS;
-
-        // Trivial-cache - keyed on $cachedcontextid
-        static $cachedcontextid;
-        static $conceptlist;
-
-        static $nothingtodo;         // To avoid processing if no glossaries / concepts are found
+        global $CFG, $USER, $GLOSSARY_EXCLUDEENTRY;
 
         // Try to get current course.
         $coursectx = $this->context->get_course_context(false);
         if (!$coursectx) {
+            // Only global glossaries will be linked.
             $courseid = 0;
         } else {
             $courseid = $coursectx->instanceid;
         }
 
-        // Initialise/invalidate our trivial cache if dealing with a different context
-        if (!isset($cachedcontextid) || $cachedcontextid !== $this->context->id) {
-            $cachedcontextid = $this->context->id;
-            $conceptlist = array();
-            $nothingtodo = false;
-        }
-
-        if (($nothingtodo === true) || (!has_capability('mod/glossary:view', $this->context))) {
-            return $text;
+        if ($this->cachecourseid != $courseid or $this->cacheuserid != $USER->id) {
+            // Invalidate the page cache.
+            $this->cacheconceptlist = null;
         }
 
-        // Create a list of all the concepts to search for.  It may be cached already.
-        if (empty($conceptlist)) {
-
-            // Find all the glossaries we need to examine
-            if (!$glossaries = $DB->get_records_sql_menu('
-                    SELECT g.id, g.name
-                      FROM {glossary} g, {course_modules} cm, {modules} m
-                     WHERE m.name = \'glossary\'
-                       AND cm.module = m.id
-                       AND cm.visible = 1
-                       AND g.id = cm.instance
-                       AND g.usedynalink != 0
-                       AND (g.course = ? OR g.globalglossary = 1)
-                  ORDER BY g.globalglossary, g.id', array($courseid))) {
-                $nothingtodo = true;
+        if (is_array($this->cacheconceptlist) and empty($GLOSSARY_EXCLUDEENTRY)) {
+            if (empty($this->cacheconceptlist)) {
                 return $text;
             }
+            return filter_phrases($text, $this->cacheconceptlist);
+        }
 
-            // Make a list of glossary IDs for searching
-            $glossarylist = implode(',', array_keys($glossaries));
-
-            // Pull out all the raw data from the database for entries, categories and aliases
-            $entries = $DB->get_records_select('glossary_entries',
-                    'glossaryid IN ('.$glossarylist.') AND usedynalink != 0 AND approved != 0 ', null, '',
-                    'id,glossaryid, concept, casesensitive, 0 AS category, fullmatch');
-
-            $categories = $DB->get_records_select('glossary_categories',
-                    'glossaryid IN ('.$glossarylist.') AND usedynalink != 0', null, '',
-                    'id,glossaryid,name AS concept, 1 AS casesensitive, 1 AS category, 1 AS fullmatch');
-
-            $aliases = $DB->get_records_sql('
-                    SELECT ga.id, ge.id AS entryid, ge.glossaryid,
-                           ga.alias AS concept, ge.concept AS originalconcept,
-                           casesensitive, 0 AS category, fullmatch
-                      FROM {glossary_alias} ga,
-                           {glossary_entries} ge
-                      WHERE ga.entryid = ge.id
-                        AND ge.glossaryid IN ('.$glossarylist.')
-                        AND ge.usedynalink != 0
-                        AND ge.approved != 0', null);
-
-            // Combine them into one big list
-            $concepts = array();
-            if ($entries and $categories) {
-                $concepts = array_merge($entries, $categories);
-            } else if ($categories) {
-                $concepts = $categories;
-            } else if ($entries) {
-                $concepts = $entries;
-            }
-
-            if ($aliases) {
-                $concepts = array_merge($concepts, $aliases);
-            }
-
-            if (!empty($concepts)) {
-                foreach ($concepts as $key => $concept) {
-                    // Trim empty or unlinkable concepts
-                    $currentconcept = trim(strip_tags($concept->concept));
-
-                    // Concept must be HTML-escaped, so do the same as format_string
-                    // to turn ampersands into &amp;.
-                    $currentconcept = replace_ampersands_not_followed_by_entity($currentconcept);
-
-                    if (empty($currentconcept)) {
-                        unset($concepts[$key]);
-                        continue;
-                    } else {
-                        $concepts[$key]->concept = $currentconcept;
-                    }
-
-                    // Rule out any small integers.  See bug 1446
-                    $currentint = intval($currentconcept);
-                    if ($currentint && (strval($currentint) == $currentconcept) && $currentint < 1000) {
-                        unset($concepts[$key]);
-                    }
-                }
-            }
-
-            if (empty($concepts)) {
-                $nothingtodo = true;
-                return $text;
-            }
+        list($glossaries, $allconcepts) = \mod_glossary\local\concept_cache::get_concepts($courseid);
 
-            usort($concepts, 'filter_glossary::sort_entries_by_length');
+        if (!$allconcepts) {
+            $this->cacheuserid = $USER->id;
+            $this->cachecourseid = $courseid;
+            $this->cacheconcepts = array();
+            return $text;
+        }
 
-            $strcategory = get_string('category', 'glossary');
+        $strcategory = get_string('category', 'glossary');
 
-            // Loop through all the concepts, setting up our data structure for the filter
-            $conceptlist = array();    // We will store all the concepts here
+        $conceptlist = array();
+        $excluded = false;
 
+        foreach ($allconcepts as $concepts) {
             foreach ($concepts as $concept) {
-                $glossaryname = str_replace(':', '-', $glossaries[$concept->glossaryid]);
-                if ($concept->category) {       // Link to a category
-                    // TODO: Fix this string usage
-                    $title = strip_tags($glossaryname.': '.$strcategory.' '.$concept->concept);
-                    $href_tag_begin = '<a class="glossary autolink category glossaryid'.$concept->glossaryid.'" title="'.$title.'" '.
-                                      'href="'.$CFG->wwwroot.'/mod/glossary/view.php?g='.$concept->glossaryid.
-                                      '&amp;mode=cat&amp;hook='.$concept->id.'">';
+                if (!empty($GLOSSARY_EXCLUDEENTRY) and $concept->id == $GLOSSARY_EXCLUDEENTRY) {
+                    $excluded = true;
+                    continue;
+                }
+                if ($concept->category) { // Link to a category.
+                    // TODO: Fix this string usage.
+                    $title = $glossaries[$concept->glossaryid] . ': ' . $strcategory . ' ' . $concept->concept;
+                    $link = new moodle_url('/mod/glossary/view.php', array('g' => $concept->glossaryid, 'mode' => 'cat', 'hook' => $concept->id));
+                    $attributes = array(
+                        'href'  => $link,
+                        'title' => $title,
+                        'class' => 'glossary autolink category glossaryid' . $concept->glossaryid);
+
                 } else { // Link to entry or alias
-                    if (!empty($concept->originalconcept)) {  // We are dealing with an alias (so show and point to original)
-                        $title = str_replace('"', "'", html_entity_decode(
-                                strip_tags($glossaryname.': '.$concept->originalconcept)));
-                        $concept->id = $concept->entryid;
-                    } else { // This is an entry
-                        // We need to remove entities from the content here because it
-                        // will be escaped by html_writer below.
-                        $title = str_replace('"', "'", html_entity_decode(
-                                strip_tags($glossaryname.': '.$concept->concept)));
-                    }
-                    // hardcoding dictionary format in the URL rather than defaulting
+                    $title = $glossaries[$concept->glossaryid] . ': ' . $concept->concept;
+                    // Hardcoding dictionary format in the URL rather than defaulting
                     // to the current glossary format which may not work in a popup.
                     // for example "entry list" means the popup would only contain
                     // a link that opens another popup.
-                    $link = new moodle_url('/mod/glossary/showentry.php', array('courseid'=>$courseid, 'eid'=>$concept->id, 'displayformat'=>'dictionary'));
+                    $link = new moodle_url('/mod/glossary/showentry.php', array('eid' => $concept->id, 'displayformat' => 'dictionary'));
                     $attributes = array(
-                        'href' => $link,
-                        'title'=> $title,
-                        'class'=> 'glossary autolink concept glossaryid'.$concept->glossaryid);
-
-                    // this flag is optionally set by resource_pluginfile()
-                    // if processing an embedded file use target to prevent getting nested Moodles
-                    if (isset($CFG->embeddedsoforcelinktarget) && $CFG->embeddedsoforcelinktarget) {
-                        $attributes['target'] = '_top';
-                    }
-
-                    $href_tag_begin = html_writer::start_tag('a', $attributes);
+                        'href'  => $link,
+                        'title' => str_replace('&amp;', '&', $title), // Undo the s() mangling.
+                        'class' => 'glossary autolink concept glossaryid' . $concept->glossaryid);
                 }
+                // This flag is optionally set by resource_pluginfile()
+                // if processing an embedded file use target to prevent getting nested Moodles.
+                if (!empty($CFG->embeddedsoforcelinktarget)) {
+                    $attributes['target'] = '_top';
+                }
+                $href_tag_begin = html_writer::start_tag('a', $attributes);
+
                 $conceptlist[] = new filterobject($concept->concept, $href_tag_begin, '</a>',
                     $concept->casesensitive, $concept->fullmatch);
             }
-
-            $conceptlist = filter_remove_duplicates($conceptlist);
         }
 
-        if (!empty($GLOSSARY_EXCLUDECONCEPTS)) {
-            $reducedconceptlist=array();
-            foreach($conceptlist as $concept) {
-                if(!in_array($concept->phrase,$GLOSSARY_EXCLUDECONCEPTS)) {
-                    $reducedconceptlist[]=$concept;
-                }
-            }
-            return filter_phrases($text, $reducedconceptlist);
+        usort($conceptlist, 'filter_glossary::sort_entries_by_length');
+
+        if (!$excluded) {
+            // Do not cache the excluded list here, it is used once per page only.
+            $this->cacheuserid = $USER->id;
+            $this->cachecourseid = $courseid;
+            $this->cacheconceptlist = $conceptlist;
         }
 
+        if (empty($conceptlist)) {
+            return $text;
+        }
         return filter_phrases($text, $conceptlist);   // Actually search for concepts!
     }
 
-
     private static function sort_entries_by_length($entry0, $entry1) {
-        $len0 = strlen($entry0->concept);
-        $len1 = strlen($entry1->concept);
+        $len0 = strlen($entry0->phrase);
+        $len1 = strlen($entry1->phrase);
 
         if ($len0 < $len1) {
             return 1;
index c8f3966..ccf54ed 100644 (file)
@@ -53,18 +53,22 @@ class filter_glossary_filter_testcase extends advanced_testcase {
                 array('course' => $course->id, 'mainglossary' => 1));
 
         // Create two entries with ampersands and one normal entry.
+        /** @var mod_glossary_generator $generator */
         $generator = $this->getDataGenerator()->get_plugin_generator('mod_glossary');
         $normal = $generator->create_content($glossary, array('concept' => 'normal'));
         $amp1 = $generator->create_content($glossary, array('concept' => 'A&B'));
         $amp2 = $generator->create_content($glossary, array('concept' => 'C&amp;D'));
 
+        filter_manager::reset_caches();
+        \mod_glossary\local\concept_cache::reset_caches();
+
         // Format text with all three entries in HTML.
         $html = '<p>A&amp;B C&amp;D normal</p>';
         $filtered = format_text($html, FORMAT_HTML, array('context' => $context));
 
         // Find all the glossary links in the result.
         $matches = array();
-        preg_match_all('~courseid=' . $course->id . '&amp;eid=([0-9]+).*?title="(.*?)"~', $filtered, $matches);
+        preg_match_all('~eid=([0-9]+).*?title="(.*?)"~', $filtered, $matches);
 
         // There should be 3 glossary links.
         $this->assertEquals(3, count($matches[1]));
index 9d099fb..d20d57f 100644 (file)
@@ -25,8 +25,8 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version  = 2013110500;
-$plugin->requires = 2013110500;  // Requires this Moodle version
+$plugin->version  = 2014040600;
+$plugin->requires = 2014040300;  // Requires this Moodle version
 $plugin->component= 'filter_glossary';
 
-$plugin->dependencies = array('mod_glossary' => 2013110500);
+$plugin->dependencies = array('mod_glossary' => 2014040600);
index 6e593f3..05eae5d 100644 (file)
@@ -114,7 +114,11 @@ class filter_tex extends moodle_text_filter {
         global $CFG, $DB;
 
         /// Do a quick check using stripos to avoid unnecessary work
-        if (!preg_match('/<tex/i',$text) and !strstr($text,'$$') and !strstr($text,'\\[') and !preg_match('/\[tex/i',$text)) { //added one more tag (dlnsk)
+        if ((!preg_match('/<tex/i', $text)) &&
+                (strpos($text,'$$') === false) &&
+                (strpos($text,'\\[') === false) &&
+                (strpos($text, '\\(') === false) &&
+                (!preg_match('/\[tex/i',$text))) {
             return $text;
         }
 
@@ -146,9 +150,20 @@ class filter_tex extends moodle_text_filter {
         // or $$ TeX expression $$
         // or \[ TeX expression \]          // original tag of MathType and TeXaide (dlnsk)
         // or [tex] TeX expression [/tex]   // somtime it's more comfortable than <tex> (dlnsk)
-        preg_match_all('/<tex(?:\s+alt=["\'](.*?)["\'])?>(.+?)<\/tex>|\$\$(.+?)\$\$|\\\\\[(.+?)\\\\\]|\\[tex\\](.+?)\\[\/tex\\]/is', $text, $matches);
+        $rules = array(
+            '<tex(?:\s+alt=["\'](.*?)["\'])?>(.+?)<\/tex>',
+            '\$\$(.+?)\$\$',
+            '\\\\\[(.+?)\\\\\]',
+            '\\\\\((.+?)\\\\\)',
+            '\\[tex\\](.+?)\\[\/tex\\]'
+        );
+        $megarule = '/' . implode($rules, '|') . '/is';
+        preg_match_all($megarule, $text, $matches);
         for ($i=0; $i<count($matches[0]); $i++) {
-            $texexp = $matches[2][$i] . $matches[3][$i] . $matches[4][$i] . $matches[5][$i];
+            $texexp = '';
+            for ($j = 0; $j < count($rules); $j++) {
+                $texexp .= $matches[$j + 2][$i];
+            }
             $alt = $matches[1][$i];
             $texexp = str_replace('<nolink>','',$texexp);
             $texexp = str_replace('</nolink>','',$texexp);
diff --git a/filter/tex/tests/filter_test.php b/filter/tex/tests/filter_test.php
new file mode 100644 (file)
index 0000000..1b03725
--- /dev/null
@@ -0,0 +1,81 @@
+<?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/>.
+
+/**
+ * Unit test for the filter_tex
+ *
+ * @package    filter_tex
+ * @copyright  2014 Damyon Wiese
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+global $CFG;
+require_once($CFG->dirroot . '/filter/tex/filter.php');
+
+
+/**
+ * Unit tests for filter_tex.
+ *
+ * Test the delimiter parsing used by the tex filter.
+ *
+ * @copyright  2014 Damyon Wiese
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class filter_tex_testcase extends advanced_testcase {
+
+    protected $filter;
+
+    protected function setUp() {
+        parent::setUp();
+        $this->resetAfterTest(true);
+        $this->filter = new filter_tex(context_system::instance(), array());
+    }
+
+    function run_with_delimiters($start, $end, $filtershouldrun) {
+        $pre = 'Some pre text';
+        $post = 'Some post text';
+        $equation = ' \sum{a^b} ';
+
+        $before = $pre . $start . $equation . $end . $post;
+
+        $after = trim($this->filter->filter($before));
+
+        if ($filtershouldrun) {
+            $this->assertNotEquals($after, $before);
+        } else {
+            $this->assertEquals($after, $before);
+        }
+    }
+
+    function test_delimiters() {
+        // First test the list of supported delimiters.
+        $this->run_with_delimiters('$$', '$$', true);
+        $this->run_with_delimiters('\\(', '\\)', true);
+        $this->run_with_delimiters('\\[', '\\]', true);
+        $this->run_with_delimiters('[tex]', '[/tex]', true);
+        $this->run_with_delimiters('<tex>', '</tex>', true);
+        $this->run_with_delimiters('<tex alt="nonsense">', '</tex>', true);
+        // Now test some cases that shouldn't be executed.
+        $this->run_with_delimiters('<textarea>', '</textarea>', false);
+        $this->run_with_delimiters('$', '$', false);
+        $this->run_with_delimiters('(', ')', false);
+        $this->run_with_delimiters('[', ']', false);
+        $this->run_with_delimiters('$$', '\\]', false);
+    }
+
+}
index 916abb7..d09245d 100644 (file)
@@ -739,6 +739,7 @@ $string['eventcoursesectionupdated'] = ' Course section updated';
 $string['eventcoursemoduleinstancelistviewed'] = 'Course module instance list viewed';
 $string['eventemailfailed'] = 'Email failed to send';
 $string['eventname'] = 'Event name';
+$string['eventunknownlogged'] = 'Unknown event';
 $string['eventusercreated'] = 'User created';
 $string['eventuserdeleted'] = 'User deleted';
 $string['eventuserlistviewed'] = 'User list viewed';
index e9c6633..d869d74 100644 (file)
@@ -5652,7 +5652,7 @@ abstract class context extends stdClass implements IteratorAggregate {
      * Is this context part of any course? If yes return course context.
      *
      * @param bool $strict true means throw exception if not found, false means return false if not found
-     * @return course_context context of the enclosing course, null if not found or exception
+     * @return context_course context of the enclosing course, null if not found or exception
      */
     public function get_course_context($strict = true) {
         if ($strict) {
@@ -6791,7 +6791,7 @@ class context_course extends context {
      * Is this context part of any course? If yes return course context.
      *
      * @param bool $strict true means throw exception if not found, false means return false if not found
-     * @return course_context context of the enclosing course, null if not found or exception
+     * @return context_course context of the enclosing course, null if not found or exception
      */
     public function get_course_context($strict = true) {
         return $this;
@@ -7257,7 +7257,7 @@ class context_block extends context {
      * Is this context part of any course? If yes return course context.
      *
      * @param bool $strict true means throw exception if not found, false means return false if not found
-     * @return course_context context of the enclosing course, null if not found or exception
+     * @return context_course context of the enclosing course, null if not found or exception
      */
     public function get_course_context($strict = true) {
         $parentcontext = $this->get_parent_context();
index 6b4bf6e..62752af 100644 (file)
@@ -37,6 +37,7 @@ defined('MOODLE_INTERNAL') || die();
  * Both events could be triggered in a row, first the uploaded, then the submitted.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 972195c..64fdabe 100644 (file)
@@ -44,6 +44,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 33870ce..e0034bd 100644 (file)
@@ -30,6 +30,7 @@ defined('MOODLE_INTERNAL') || die();
  * All other event classes must extend this class.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Petr Skoda {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  *
@@ -338,7 +339,7 @@ abstract class base implements \IteratorAggregate {
         }
 
         if (!class_exists($classname)) {
-            return false;
+            return self::restore_unknown($data, $logextra);
         }
         $event = new $classname();
         if (!($event instanceof \core\event\base)) {
@@ -370,6 +371,27 @@ abstract class base implements \IteratorAggregate {
         return $event;
     }
 
+    /**
+     * Restore unknown event.
+     *
+     * @param array $data
+     * @param array $logextra
+     * @return unknown_logged
+     */
+    protected static final function restore_unknown(array $data, array $logextra) {
+        $classname = '\core\event\unknown_logged';
+
+        /** @var unknown_logged $event */
+        $event = new $classname();
+        $event->restored = true;
+        $event->triggered = true;
+        $event->dispatched = true;
+        $event->data = $data;
+        $event->logextra = $logextra;
+
+        return $event;
+    }
+
     /**
      * Create fake event from legacy log data.
      *
index 28c03c1..495a643 100644 (file)
@@ -39,6 +39,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2013 onwards Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 1ac2850..3bd1005 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * blog comment created event.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index cf8e7da..4e07272 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * blog comment deleted event.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 6da91bb..a22092d 100644 (file)
@@ -36,6 +36,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2013 onwards Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 1b3f6b1..c476189 100644 (file)
@@ -21,7 +21,7 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Event for when a new blog entry is added..
  *
- * @package    core_blog
+ * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -31,7 +31,8 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when a blog entry is created.
  *
- * @package    core_blog
+ * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 467d811..e2acde8 100644 (file)
@@ -16,7 +16,7 @@
 /**
  * Event for when a new blog entry is deleted.
  *
- * @package    core_blog
+ * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -29,7 +29,8 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Event for when a new blog entry is deleted.
  *
- * @package    core_blog
+ * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index ff9686b..dcfec20 100644 (file)
@@ -30,6 +30,7 @@ defined('MOODLE_INTERNAL') || die();
  * Event to be triggered when a blog entry is updated.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index b9b83a6..9dceaca 100644 (file)
@@ -35,6 +35,7 @@ defined('MOODLE_INTERNAL') || die();
  *     -int repeatid: Id of the parent event if present, else 0.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 329aed5..296ad68 100644 (file)
@@ -35,6 +35,7 @@ defined('MOODLE_INTERNAL') || die();
  *     -int repeatid: Id of the parent event if present, else 0.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index ffab5b9..6226502 100644 (file)
@@ -35,6 +35,7 @@ defined('MOODLE_INTERNAL') || die();
  *     -int repeatid: Id of the parent event if present, else 0.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 onwards Ankit Agarwal <ankit.agrr@gmail.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index cfe435d..ee748e4 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * Cohort created event class.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Dan Poltawski <dan@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index ccc2ccd..4b9c520 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * Cohort deleted event class.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Dan Poltawski <dan@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 8dc153d..a32c341 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * User added to a cohort event class.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Dan Poltawski <dan@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index e42868a..6145fa2 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * User removed from a cohort event class.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Dan Poltawski <dan@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 7ee1226..e023643 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * Cohort updated event class.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Dan Poltawski <dan@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 2e18f69..539bfc4 100644 (file)
@@ -38,6 +38,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index be04218..de7829f 100644 (file)
@@ -38,6 +38,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index fbea09d..4964ee4 100644 (file)
@@ -32,6 +32,7 @@ defined('MOODLE_INTERNAL') || die();
  * This class has to be extended by any event which is triggred while viewing comment.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 797ad37..9f7ab5f 100644 (file)
@@ -37,6 +37,7 @@ debugging('core\event\content_viewed has been deprecated. Please extend base eve
  * This class has been deprecated, please extend base event or other relevent abstract class.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Ankit Agarwal
  * @deprecated since Moodle 2.7
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index c131f27..4e60ffc 100644 (file)
@@ -22,6 +22,7 @@ defined('MOODLE_INTERNAL') || die();
  * Course category created event.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 63333b4..e14dc68 100644 (file)
@@ -28,6 +28,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 2cb7739..d12bbaa 100644 (file)
@@ -22,6 +22,7 @@ defined('MOODLE_INTERNAL') || die();
  * Course category updated event.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 300bcdc..05a43ee 100644 (file)
@@ -21,7 +21,8 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Event when course completed.
  *
- * @package    core_event
+ * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 9ffa4f6..d687080 100644 (file)
@@ -30,6 +30,7 @@ defined('MOODLE_INTERNAL') || die();
  * Event when course module completion is updated.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 05a59d1..fe64a58 100644 (file)
@@ -28,6 +28,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 93e6bab..16fee48 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 357b9cd..fc999d5 100644 (file)
@@ -30,6 +30,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 6233bfb..88d8067 100644 (file)
@@ -22,6 +22,7 @@ defined('MOODLE_INTERNAL') || die();
  * Event when course module completion is updated.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index c73f711..fd0aebb 100644 (file)
@@ -39,6 +39,7 @@ defined('MOODLE_INTERNAL') || die();
  * Class for event to be triggered when a new course module is created.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
  */
index 82d01d1..fa539d6 100644 (file)
@@ -38,6 +38,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
  */
index 87c222a..f4a5782 100644 (file)
@@ -37,6 +37,7 @@ defined('MOODLE_INTERNAL') || die();
  *     \mod_chat\event\course_module_instance_list_viewed extends \core\event\course_module_instance_list_viewed
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2013 onwards Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index a7c2df1..6534c5c 100644 (file)
@@ -32,6 +32,7 @@ defined('MOODLE_INTERNAL') || die();
  *
  * @deprecated Since Moodle 2.7
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index e1069d6..976987b 100644 (file)
@@ -39,6 +39,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
  */
index 9f9b654..4c88c4b 100644 (file)
@@ -31,6 +31,7 @@ defined('MOODLE_INTERNAL') || die();
  * Class for event to be triggered when a course module is viewed.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2013 onwards Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 02aa67c..f3191d2 100644 (file)
@@ -35,6 +35,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 91531ef..59c6abe 100644 (file)
@@ -35,6 +35,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 24e046a..cae5e3a 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * Event for viewing the list of course resources.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Marina Glancy
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 02a9dd2..8858f4b 100644 (file)
@@ -32,6 +32,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index bec63f3..dd92950 100644 (file)
@@ -36,6 +36,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index a7d8bc3..9d3be66 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index d0220da..90830ab 100644 (file)
@@ -22,6 +22,7 @@ defined('MOODLE_INTERNAL') || die();
  * Email failed event.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index ff92010..a9faa24 100644 (file)
@@ -15,9 +15,9 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * core_group created event.
+ * Group created event.
  *
- * @package    core_group
+ * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -26,9 +26,10 @@ namespace core\event;
 defined('MOODLE_INTERNAL') || die();
 
 /**
- * core_group created event class.
+ * Group created event class.
  *
- * @package    core_group
+ * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index e1cfca4..f1879fb 100644 (file)
@@ -15,9 +15,9 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * core_group deleted event.
+ * Group deleted event.
  *
- * @package    core_group
+ * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -26,9 +26,10 @@ namespace core\event;
 defined('MOODLE_INTERNAL') || die();
 
 /**
- * core_group deleted event class.
+ * Group deleted event class.
  *
- * @package    core_group
+ * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index a248f91..674fd7e 100644 (file)
@@ -15,9 +15,9 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * core_group member added event.
+ * Group member added event.
  *
- * @package    core_group
+ * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -26,7 +26,7 @@ namespace core\event;
 defined('MOODLE_INTERNAL') || die();
 
 /**
- * core_group member added event class.
+ * Group member added event class.
  *
  * @property-read array $other {
  *      Extra information about event.
@@ -35,7 +35,8 @@ defined('MOODLE_INTERNAL') || die();
  *      @type int itemid id of item.
  * }
  *
- * @package    core_group
+ * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 8557359..3842a41 100644 (file)
@@ -15,9 +15,9 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * core_group member removed event.
+ * Group member removed event.
  *
- * @package    core_group
+ * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -26,9 +26,10 @@ namespace core\event;
 defined('MOODLE_INTERNAL') || die();
 
 /**
- * core_group member removed event class.
+ * Group member removed event class.
  *
- * @package    core_group
+ * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 4b03799..e5d61f9 100644 (file)
@@ -15,7 +15,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * core_group updated event.
+ * Group updated event.
  *
  * @package    core_group
  * @copyright  2013 Frédéric Massart
@@ -26,9 +26,10 @@ namespace core\event;
 defined('MOODLE_INTERNAL') || die();
 
 /**
- * core_group updated event class.
+ * Group updated event class.
  *
- * @package    core_group
+ * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index b4ecb1a..e5a00e3 100644 (file)
@@ -15,7 +15,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * core_group grouping created event.
+ * Grouping created event.
  *
  * @package    core_group
  * @copyright  2013 Frédéric Massart
@@ -26,9 +26,10 @@ namespace core\event;
 defined('MOODLE_INTERNAL') || die();
 
 /**
- * core_group grouping created event class.
+ * Grouping created event class.
  *
- * @package    core_group
+ * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 3603be9..a3d0efc 100644 (file)
@@ -15,9 +15,9 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * core_group grouping deleted event.
+ * Grouping deleted event.
  *
- * @package    core_group
+ * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -26,9 +26,10 @@ namespace core\event;
 defined('MOODLE_INTERNAL') || die();
 
 /**
- * core_group grouping deleted event class.
+ * Grouping deleted event class.
  *
- * @package    core_group
+ * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 4e351dd..2dfca36 100644 (file)
@@ -15,9 +15,9 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * core_group grouping updated event.
+ * Grouping updated event.
  *
- * @package    core_group
+ * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -26,9 +26,10 @@ namespace core\event;
 defined('MOODLE_INTERNAL') || die();
 
 /**
- * core_group grouping updated event class.
+ * Grouping updated event class.
  *
- * @package    core_group
+ * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 7ad49fb..1eb4996 100644 (file)
@@ -28,6 +28,7 @@
  * }
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 4967536..da60d86 100644 (file)
@@ -28,6 +28,7 @@
  * }
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 738bb7d..879b4a6 100644 (file)
@@ -22,6 +22,7 @@ defined('MOODLE_INTERNAL') || die();
  * New event manager class.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Petr Skoda {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 6ea7dd8..5d2c94e 100644 (file)
@@ -18,6 +18,7 @@
  * Message contact added event class.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 3d79fbd..6b1cdf6 100644 (file)
@@ -18,6 +18,7 @@
  * Message contact blocked event class.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 78c0d04..2ca36ea 100644 (file)
@@ -18,6 +18,7 @@
  * Message contact removed event class.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 2475511..c931462 100644 (file)
@@ -18,6 +18,7 @@
  * Message contact unblocked event class.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 664f2f2..3ed0a5f 100644 (file)
@@ -24,6 +24,7 @@
  * }
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 3aad156..2240fcf 100644 (file)
@@ -24,6 +24,7 @@
  * }
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index cf9cb13..56b70c4 100644 (file)
@@ -18,6 +18,7 @@
  * Mnet access control created event class.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 79ac0ec..b2badfa 100644 (file)
@@ -18,6 +18,7 @@
  * Mnet access control updated event class.
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index e4a804b..fe2f208 100644 (file)
@@ -38,6 +38,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index bf15884..53403b7 100644 (file)
@@ -38,6 +38,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 54c8fb3..79cc5aa 100644 (file)
@@ -38,6 +38,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 5765111..58a688e 100644 (file)
@@ -32,6 +32,7 @@ defined('MOODLE_INTERNAL') || die();
  * Class for event to be triggered when a note is viewed.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index b5f2dd1..50b9475 100644 (file)
@@ -21,7 +21,8 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Event when role allow assignments is updated.
  *
- * @package    core_event
+ * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 9451cfa..3e3c6ac 100644 (file)
@@ -21,7 +21,8 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Event when role allow override is updated.
  *
- * @package    core_event
+ * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 7b96dde..0d03614 100644 (file)
@@ -21,7 +21,8 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Event when role allow switch is updated.
  *
- * @package    core_event
+ * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index cad0a1b..79b5639 100644 (file)
@@ -30,6 +30,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Petr Skoda {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 9347479..5c65f95 100644 (file)
@@ -21,7 +21,8 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Role updated event.
  *
- * @package    core_event
+ * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index de3e963..9a52582 100644 (file)
@@ -29,7 +29,8 @@ defined('MOODLE_INTERNAL') || die();
  *      @type string archetype role type.
  * }
  *
- * @package    core_event
+ * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 4521ab3..4a0908f 100644 (file)
@@ -30,6 +30,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Petr Skoda {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 9b6e9ac..a94c78b 100644 (file)
@@ -25,6 +25,7 @@
  * }
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 55c1356..6077b8a 100644 (file)
@@ -25,6 +25,7 @@
  * }
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 18adc67..5c4b8fc 100644 (file)
@@ -25,6 +25,7 @@
  * }
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 6acc93c..70e2518 100644 (file)
@@ -25,6 +25,7 @@
  * }
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 8381097..a2059a5 100644 (file)
@@ -25,6 +25,7 @@
  * }
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
diff --git a/lib/classes/event/unknown_logged.php b/lib/classes/event/unknown_logged.php
new file mode 100644 (file)
index 0000000..a0e7544
--- /dev/null
@@ -0,0 +1,41 @@
+<?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/>.
+
+namespace core\event;
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Unknown event class.
+ *
+ * @package    core
+ * @since      Moodle 2.7
+ * @copyright  2014 Petr Skoda
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class unknown_logged extends base {
+    public function init() {
+        throw new \coding_exception('unknown events cannot be triggered');
+    }
+
+    public static function get_name() {
+        return get_string('eventunknownlogged', 'core');
+    }
+
+    public function get_description() {
+        return 'Unknown event (' . $this->eventname . ')';
+    }
+}
index ec91dc3..88ce8ca 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * Event when new user profile is created.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 37d9edb..dcfdddb 100644 (file)
@@ -39,6 +39,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 825eb53..5338cd6 100644 (file)
@@ -35,6 +35,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 4c7a905..7339566 100644 (file)
@@ -36,6 +36,7 @@ defined('MOODLE_INTERNAL') || die();
  * Event when user is unenrolled from a course.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 5bfad22..02c5c7c 100644 (file)
@@ -35,6 +35,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index ae77611..ba3f374 100644 (file)
@@ -17,7 +17,7 @@
 /**
  * Grade edited event.
  *
- * @package    core_grades
+ * @package    core
  * @copyright  2014 Petr Skoda
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
@@ -37,7 +37,8 @@ defined('MOODLE_INTERNAL') || die();
  *     -bool overridden: Is this grade override?
  *     -float finalgrade: the final grade value.
  *
- * @package    core_grades
+ * @package    core
+ * @since      Moodle 2.7
  * @copyright  2013 Petr Skoda
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 315b376..6cb6210 100644 (file)
@@ -26,6 +26,7 @@
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index ec94f35..6966893 100644 (file)
@@ -18,6 +18,7 @@
  * User login event.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index bf88da9..b292c58 100644 (file)
@@ -37,6 +37,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index f332ae1..310e5e6 100644 (file)
@@ -35,6 +35,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 7ea66cf..c671792 100644 (file)
@@ -37,6 +37,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.7
  * @copyright  2014 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 919ecc7..7bc8ba8 100644 (file)
@@ -26,6 +26,7 @@
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index af7c04f..69e36c5 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * Event when user profile is updated.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index a2f3e8c..b40cec2 100644 (file)
@@ -35,6 +35,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 7d82a95..181dbb7 100644 (file)
@@ -37,6 +37,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 9aa7e24..46f5199 100644 (file)
@@ -35,6 +35,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 7832e0a..517bea8 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * core webservice service deleted event class.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 121f7a3..dacc33b 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * core webservice service updated event class.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 4bf7c94..d27fdb1 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * core webservice service user added event class.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 7114b47..95b71c5 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * core webservice service user removed event class.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index db241df..1eda6b0 100644 (file)
@@ -35,6 +35,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index e674929..e5498c5 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * core webservice token sent event class.
  *
  * @package    core
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 5fcee40..96488db 100644 (file)
@@ -499,13 +499,10 @@ class core_grades_external extends external_api {
      * @since Moodle 2.7
      */
     public static function update_grades_returns() {
-        return new external_single_structure(
-            array (
-                'result' => new external_value(
-                    PARAM_INT,
-                    'A value like ' . GRADE_UPDATE_OK . ' => OK, ' . GRADE_UPDATE_FAILED . ' => FAILED
-                    as defined in lib/grade/constants.php')
-            )
+        return new external_value(
+            PARAM_INT,
+            'A value like ' . GRADE_UPDATE_OK . ' => OK, ' . GRADE_UPDATE_FAILED . ' => FAILED
+            as defined in lib/grade/constants.php'
         );
     }
 }
index e6d13b3..06612bb 100644 (file)
@@ -107,14 +107,29 @@ function css_write_file($filename, $content) {
 /**
  * Takes CSS and chunks it if the number of selectors within it exceeds $maxselectors.
  *
+ * The chunking will not split a group of selectors, or a media query. That means that
+ * if n > $maxselectors and there are n selectors grouped together,
+ * they will not be chunked and you could end up with more selectors than desired.
+ * The same applies for a media query that has more than n selectors.
+ *
+ * Also, as we do not split group of selectors or media queries, the chunking might
+ * not be as optimal as it could be, having files with less selectors than it could
+ * potentially contain.
+ *
+ * String functions used here are not compliant with unicode characters. But that is
+ * not an issue as the syntax of CSS is using ASCII codes. Even if we have unicode
+ * characters in comments, or in the property 'content: ""', it will behave correcly.
+ *
+ * Please note that this strips out the comments if chunking happens.
+ *
  * @param string $css The CSS to chunk.
  * @param string $importurl The URL to use for import statements.
  * @param int $maxselectors The number of selectors to limit a chunk to.
- * @param int $buffer The buffer size to use when chunking. You shouldn't need to reduce this
- *      unless you are lowering the maximum selectors.
+ * @param int $buffer Not used any more.
  * @return array An array of CSS chunks.
  */
 function css_chunk_by_selector_count($css, $importurl, $maxselectors = 4095, $buffer = 50) {
+
     // Check if we need to chunk this CSS file.
     $count = substr_count($css, ',') + substr_count($css, '{');
     if ($count < $maxselectors) {
@@ -122,44 +137,116 @@ function css_chunk_by_selector_count($css, $importurl, $maxselectors = 4095, $bu
         return array($css);
     }
 
-    // Chunk time ?!
-    // Split the CSS by array, making sure to save the delimiter in the process.
-    $parts = preg_split('#([,\}])#', $css, null, PREG_SPLIT_DELIM_CAPTURE + PREG_SPLIT_NO_EMPTY);
-    // We need to chunk the array. Each delimiter is stored separately so we multiple by 2.
-    // We also subtract 100 to give us a small buffer just in case.
-    $parts = array_chunk($parts, $maxselectors * 2 - $buffer * 2);
-    $css = array();
-    $partcount = count($parts);
-    foreach ($parts as $key => $chunk) {
-        if (end($chunk) === ',') {
-            // Damn last element was a comma.
-            // Pretty much the only way to deal with this is to take the styles from the end of the
-            // comma separated chain of selectors and apply it to the last selector we have here in place
-            // of the comma.
-            // Unit tests are essential for making sure this works.
-            $styles = false;
-            $i = $key;
-            while ($styles === false && $i < ($partcount - 1)) {
-                $i++;
-                $nextpart = $parts[$i];
-                foreach ($nextpart as $style) {
-                    if (strpos($style, '{') !== false) {
-                        $styles = preg_replace('#^[^\{]+#', '', $style);
-                        break;
-                    }
+    $chunks = array();                  // The final chunks.
+    $offsets = array();                 // The indexes to chunk at.
+    $offset = 0;                        // The current offset.
+    $selectorcount = 0;                 // The number of selectors since the last split.
+    $lastvalidoffset = 0;               // The last valid index to split at.
+    $lastvalidoffsetselectorcount = 0;  // The number of selectors used at the time were could split.
+    $inrule = 0;                        // The number of rules we are in, should not be greater than 1.
+    $inmedia = false;                   // Whether or not we are in a media query.
+    $mediacoming = false;               // Whether or not we are expeting a media query.
+    $currentoffseterror = null;         // Not null when we have recorded an error for the current split.
+    $offseterrors = array();            // The offsets where we found errors.
+
+    // Remove the comments. Because it's easier, safer and probably a lot of other good reasons.
+    $css = preg_replace('#/\*(.*?)\*/#s', '', $css);
+    $strlen = strlen($css);
+
+    // Walk through the CSS content character by character.
+    for ($i = 1; $i <= $strlen; $i++) {
+        $char = $css[$i - 1];
+        $offset = $i;
+
+        // Is that a media query that I see coming towards us?
+        if ($char === '@') {
+            if (!$inmedia && substr($css, $offset, 5) === 'media') {
+                $mediacoming = true;
+            }
+        }
+
+        // So we are entering a rule or a media query...
+        if ($char === '{') {
+            if ($mediacoming) {
+                $inmedia = true;
+                $mediacoming = false;
+            } else {
+                $inrule++;
+                $selectorcount++;
+            }
+        }
+
+        // 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 === ',') {
+            $selectorcount++;
+        }
+
+        // We reached the end of something.
+        if ($char === '}') {
+            // Oh, we are in a media query.
+            if ($inmedia) {
+                if (!$inrule) {
+                    // This is the end of the media query.
+                    $inmedia = false;
+                } else {
+                    // We were in a rule, in the media query.
+                    $inrule--;
                 }
+            } else {
+                $inrule--;
+            }
+
+            // We are not in a media query, and there is no pending rule, it is safe to split here.
+            if (!$inmedia && !$inrule) {
+                $lastvalidoffset = $offset;
+                $lastvalidoffsetselectorcount = $selectorcount;
             }
-            if ($styles === false) {
-                $styles = '/** Error chunking CSS **/';
+        }
+
+        // Alright, this is splitting time...
+        if ($selectorcount > $maxselectors) {
+            if (!$lastvalidoffset) {
+                // We must have reached more selectors into one set than we were allowed. That means that either
+                // the chunk size value is too small, or that we have a gigantic group of selectors, or that a media
+                // query contains more selectors than the chunk size. We have to ignore this because we do not
+                // support split inside a group of selectors or media query.
+                if ($currentoffseterror === null) {
+                    $currentoffseterror = $offset;
+                    $offseterrors[] = $currentoffseterror;
+                }
             } else {
-                $styles .= '}';
+                // We identify the offset to split at and reset the number of selectors found from there.
+                $offsets[] = $lastvalidoffset;
+                $selectorcount = $selectorcount - $lastvalidoffsetselectorcount;
+                $lastvalidoffset = 0;
+                $currentoffseterror = null;
             }
-            array_pop($chunk);
-            array_push($chunk, $styles);
         }
-        $css[] = join('', $chunk);
     }
-    // The array $css now contains CSS split into perfect sized chunks.
+
+    // Report offset errors.
+    if (!empty($offseterrors)) {
+        debugging('Could not find a safe place to split at offset(s): ' . implode(', ', $offseterrors) . '. Those were ignored.',
+            DEBUG_DEVELOPER);
+    }
+
+    // Now that we have got the offets, we can chunk the CSS.
+    $offsetcount = count($offsets);
+    foreach ($offsets as $key => $index) {
+        $start = 0;
+        if ($key > 0) {
+            $start = $offsets[$key - 1];
+        }
+        // From somewhere up to the offset.
+        $chunks[] = substr($css, $start, $index - $start);
+    }
+    // Add the last chunk (if there is one), from the last offset to the end of the string.
+    if (end($offsets) != $strlen) {
+        $chunks[] = substr($css, end($offsets));
+    }
+
+    // The array $chunks now contains CSS split into perfect sized chunks.
     // Import statements can only appear at the very top of a CSS file.
     // Imported sheets are applied in the the order they are imported and
     // are followed by the contents of the CSS.
@@ -170,7 +257,7 @@ function css_chunk_by_selector_count($css, $importurl, $maxselectors = 4095, $bu
     // followed by the contents of the final chunk in the actual sheet.
     $importcss = '';
     $slashargs = strpos($importurl, '.php?') === false;
-    $parts = count($css);
+    $parts = count($chunks);
     for ($i = 1; $i < $parts; $i++) {
         if ($slashargs) {
             $importcss .= "@import url({$importurl}/chunk{$i});\n";
@@ -178,10 +265,10 @@ function css_chunk_by_selector_count($css, $importurl, $maxselectors = 4095, $bu
             $importcss .= "@import url({$importurl}&chunk={$i});\n";
         }
     }
-    $importcss .= end($css);
-    $css[key($css)] = $importcss;
+    $importcss .= end($chunks);
+    $chunks[key($chunks)] = $importcss;
 
-    return $css;
+    return $chunks;
 }
 
 /**
index d4f5461..1897b76 100644 (file)
@@ -285,8 +285,7 @@ function css_minify_css($files) {
  * @return int number of failed events
  */
 function events_trigger($eventname, $eventdata) {
-    // TODO: uncomment after conversion of all events in standard distribution
-    // debugging('events_trigger() is deprecated, please use new events instead', DEBUG_DEVELOPER);
+    debugging('events_trigger() is deprecated, please use new events instead', DEBUG_DEVELOPER);
     return events_trigger_legacy($eventname, $eventdata);
 }
 
@@ -4021,7 +4020,7 @@ function get_context_url(context $context) {
  * @deprecated since 2.2
  * @see context::get_course_context()
  * @param context $context
- * @return course_context context of the enclosing course, null if not found or exception
+ * @return context_course context of the enclosing course, null if not found or exception
  */
 function get_course_context(context $context) {
     debugging('get_course_context() is deprecated, please use $context->get_course_context(true) instead.', DEBUG_DEVELOPER);
index cbf5992..12dc9eb 100644 (file)
@@ -81,7 +81,7 @@ class mariadb_native_moodle_database extends mysqli_native_moodle_database {
     public function get_server_info() {
         $version = $this->mysqli->server_info;
         $matches = null;
-        if (preg_match('/^5\.5\.5-(10\..+)-MariaDB$/i', $version, $matches)) {
+        if (preg_match('/^5\.5\.5-(10\..+)-MariaDB/i', $version, $matches)) {
             // Looks like MariaDB decided to use these weird version numbers for better BC with MySQL...
             $version = $matches[1];
         }
index 424312f..05c3bc8 100644 (file)
  */
 
 $string['alignment'] = 'Alignment';
-$string['alignment_baseline'] = 'Default (baseline)';
 $string['alignment_bottom'] = 'Bottom';
 $string['alignment_left'] = 'Left';
 $string['alignment_middle'] = 'Middle';
 $string['alignment_right'] = 'Right';
-$string['alignment_sub'] = 'Subscript';
-$string['alignment_super'] = 'Superscript';
-$string['alignment_textbottom'] = 'Text bottom';
-$string['alignment_texttop'] = 'Text top';
 $string['alignment_top'] = 'Top';
 $string['browserepositories'] = 'Browse repositories...';
-$string['constrain'] = 'Keep ratio';
+$string['constrain'] = 'Auto size';
 $string['createimage'] = 'Insert image';
+$string['customstyle'] = 'Custom style';
 $string['enteralt'] = 'Describe this image for someone who cannot see it';
 $string['enterurl'] = 'Enter URL';
 $string['height'] = 'Height';
+$string['imageproperties'] = 'Image properties';
 $string['presentation'] = 'Description not necessary';
 $string['pluginname'] = 'Image';
 $string['presentationoraltrequired'] = 'Images must have a description, except if the description is marked as not necessary.';
 $string['preview'] = 'Preview';
+$string['saveimage'] = 'Save image';
 $string['width'] = 'Width';
index a3279e7..c6c9ad2 100644 (file)
@@ -32,19 +32,16 @@ function atto_image_strings_for_js() {
 
     $strings = array(
         'alignment',
-        'alignment_baseline',
         'alignment_bottom',
         'alignment_left',
         'alignment_middle',
         'alignment_right',
-        'alignment_sub',
-        'alignment_super',
-        'alignment_textbottom',
-        'alignment_texttop',
         'alignment_top',
         'browserepositories',
         'constrain',
-        'createimage',
+        'saveimage',
+        'imageproperties',
+        'customstyle',
         'enterurl',
         'enteralt',
         'height',
index 61d4776..3d9ee6a 100644 (file)
@@ -1,6 +1,9 @@
 .atto_image_preview {
     max-width: 150px;
     max-height: 150px;
+}
+.atto_image_preview_box {
+    height: 150px;
     margin-bottom: 1em;
 }
 
index d1ee9b8..47e45b0 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 8b5f697..632e4e1 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 d1ee9b8..47e45b0 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 49208ab..333dc57 100644 (file)
@@ -32,6 +32,7 @@
  */
 
 var CSS = {
+        RESPONSIVE: 'img-responsive',
         INPUTALIGNMENT: 'atto_image_alignment',
         INPUTALT: 'atto_image_altentry',
         INPUTHEIGHT: 'atto_image_heightentry',
@@ -43,57 +44,53 @@ var CSS = {
         IMAGEBROWSER: 'openimagebrowser',
         IMAGEPRESENTATION: 'atto_image_presentation',
         INPUTCONSTRAIN: 'atto_image_constrain',
-        IMAGEPREVIEW: 'atto_image_preview'
+        INPUTCUSTOMSTYLE: 'atto_image_customstyle',
+        IMAGEPREVIEW: 'atto_image_preview',
+        IMAGEPREVIEWBOX: 'atto_image_preview_box'
     },
     ALIGNMENTS = [
         // Vertical alignment.
         {
-            name: 'baseline',
-            str: 'alignment_baseline',
-            value: 'vertical-align'
-        }, {
-            name: 'sub',
-            str: 'alignment_sub',
-            value: 'vertical-align'
-        }, {
-            name: 'super',
-            str: 'alignment_super',
-            value: 'vertical-align'
-        }, {
-            name: 'top',
-            str: 'alignment_top',
-            value: 'vertical-align'
-        }, {
             name: 'text-top',
-            str: 'alignment_texttop',
-            value: 'vertical-align'
+            str: 'alignment_top',
+            value: 'vertical-align',
+            margin: '0 .5em'
         }, {
             name: 'middle',
             str: 'alignment_middle',
-            value: 'vertical-align'
-        }, {
-            name: 'bottom',
-            str: 'alignment_bottom',
-            value: 'vertical-align'
+            value: 'vertical-align',
+            margin: '0 .5em'
         }, {
             name: 'text-bottom',
-            str: 'alignment_textbottom',
-            value: 'vertical-align'
+            str: 'alignment_bottom',
+            value: 'vertical-align',
+            margin: '0 .5em',
+            isDefault: true
         },
 
         // Floats.
         {
             name: 'left',
             str: 'alignment_left',
-            value: 'float'
+            value: 'float',
+            margin: '0 .5em 0 0'
         }, {
             name: 'right',
             str: 'alignment_right',
-            value: 'float'
+            value: 'float',
+            margin: '0 0 .5em 0'
+        }, {
+            name: 'customstyle',
+            str: 'customstyle',
+            value: 'style'
         }
-    ];
+    ],
+
+    REGEX = {
+        ISPERCENT: /\d+%/
+    },
 
-var COMPONENTNAME = 'atto_image',
+    COMPONENTNAME = 'atto_image',
 
     TEMPLATE = '' +
             '<form class="atto_form">' +
@@ -141,15 +138,19 @@ var COMPONENTNAME = 'atto_image',
                         '<option value="{{value}}:{{name}};">{{get_string str ../component}}</option>' +
                     '{{/each}}' +
                 '</select>' +
+                // Hidden input to store custom styles.
+                '<input type="hidden" class="{{CSS.INPUTCUSTOMSTYLE}}"/>' +
                 '<br/>' +
 
                 // 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;"/>' +
+                '</div>' +
                 '<br/>' +
 
                 // Add the submit button and close the form.
-                '<button class="{{CSS.INPUTSUBMIT}}" type="submit">{{get_string "createimage" component}}</button>' +
+                '<button class="{{CSS.INPUTSUBMIT}}" type="submit">{{get_string "saveimage" component}}</button>' +
                 '</div>' +
             '</form>',
 
@@ -158,7 +159,8 @@ var COMPONENTNAME = 'atto_image',
                 '{{#if width}}width="{{width}}" {{/if}}' +
                 '{{#if height}}height="{{height}}" {{/if}}' +
                 '{{#if presentation}}role="presentation" {{/if}}' +
-                '{{#if alignment}}style="{{alignment}}" {{/if}}' +
+                'style="{{alignment}}{{margin}}{{customstyle}}"' +
+                '{{#if classlist}}class="{{classlist}}" {{/if}}' +
                 '/>';
 
 Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.EditorPlugin, [], {
@@ -247,7 +249,7 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
         }
 
         var dialogue = this.getDialogue({
-            headerContent: M.util.get_string('createimage', COMPONENTNAME),
+            headerContent: M.util.get_string('imageproperties', COMPONENTNAME),
             width: '480px',
             focusAfterHide: true
         });
@@ -278,28 +280,33 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
             currentwidth = input.get('value');
             if (currentwidth === '') {
                 input.set('value', this.width);
-                currentwidth = this.width;
+                currentwidth = "" + this.width;
             }
             input = self._form.one('.' + CSS.INPUTHEIGHT);
             currentheight = input.get('value');
             if (currentheight === '') {
                 input.set('value', this.height);
-                currentheight = this.height;
+                currentheight = "" + this.height;
             }
             input = self._form.one('.' + CSS.IMAGEPREVIEW);
             input.set('src', this.src);
             input.setStyle('display', 'inline');
 
-            if (this.width === 0) {
-                this.width = 1;
-            }
-            if (this.height === 0) {
-                this.height = 1;
-            }
             input = self._form.one('.' + CSS.INPUTCONSTRAIN);
-            widthRatio = Math.round(parseInt(currentwidth, 10) / this.width);
-            heightRatio = Math.round(parseInt(currentheight, 10) / this.height);
-            input.set('checked', widthRatio === heightRatio);
+            if (currentwidth.match(REGEX.ISPERCENT) && currentheight.match(REGEX.ISPERCENT)) {
+                input.set('checked', currentwidth === currentheight);
+            } else {
+                if (this.width === 0) {
+                    this.width = 1;
+                }
+                if (this.height === 0) {
+                    this.height = 1;
+                }
+                // This is the same as comparing to 3 decimal places.
+                widthRatio = Math.round(1000*parseInt(currentwidth, 10) / this.width);
+                heightRatio = Math.round(1000*parseInt(currentheight, 10) / this.height);
+                input.set('checked', widthRatio === heightRatio);
+            }
 
             // Centre the dialogue once the preview image has loaded.
             self.getDialogue().centerDialogue();
@@ -337,6 +344,11 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
         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.INPUTCONSTRAIN).on('change', function(event) {
+            if (event.target.get('checked')) {
+                this._autoAdjustHeight();
+            }
+        }, this);
         this._form.one('.' + CSS.INPUTURL).on('blur', this._urlChanged, this);
         this._form.one('.' + CSS.INPUTSUBMIT).on('click', this._setImage, this);
 
@@ -358,19 +370,36 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
     _autoAdjustHeight: function() {
         var currentWidth, newHeight, currentHeight;
 
+        // 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 (!this._form.one('.' + CSS.INPUTCONSTRAIN).get('checked')) {
-            currentWidth = parseInt(this._form.one('.' + CSS.INPUTWIDTH).get('value'), 10);
-            currentHeight = parseInt(this._form.one('.' + CSS.INPUTHEIGHT).get('value'), 10);
+            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;
         }
-        currentWidth = parseInt(this._form.one('.' + CSS.INPUTWIDTH).get('value'), 10);
-        newHeight = Math.round((currentWidth / this._imageRawWidth) * this._imageRawHeight);
 
-        this._form.one('.' + CSS.INPUTHEIGHT).set('value', newHeight);
-        this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', newHeight);
-        this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', currentWidth);
+        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);
+
+            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);
+            }
+        }
     },
 
     /**
@@ -382,19 +411,35 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
     _autoAdjustWidth: function() {
         var currentHeight, newWidth;
 
+        // 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 (!this._form.one('.' + CSS.INPUTCONSTRAIN).get('checked')) {
-            currentWidth = parseInt(this._form.one('.' + CSS.INPUTWIDTH).get('value'), 10);
-            currentHeight = parseInt(this._form.one('.' + CSS.INPUTHEIGHT).get('value'), 10);
+            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 = parseInt(this._form.one('.' + CSS.INPUTHEIGHT).get('value'), 10);
-        newWidth = Math.round((currentHeight / this._imageRawHeight) * this._imageRawWidth);
+        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);
 
-        this._form.one('.' + CSS.INPUTWIDTH).set('value', newWidth);
-        this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('width', newWidth);
-        this._form.one('.' + CSS.IMAGEPREVIEW).setAttribute('height', currentHeight);
+            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);
+            }
+        }
     },
 
     /**
@@ -428,15 +473,32 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
      */
     _applyImageProperties: function(form) {
         var properties = this._getSelectedImageProperties(),
-            img = form.one('.' + CSS.IMAGEPREVIEW);
+            img = form.one('.' + CSS.IMAGEPREVIEW),
+            i;
 
         if (properties === false) {
             img.setStyle('display', 'none');
+            // Set the default alignment.
+            for (i in ALIGNMENTS) {
+                if (ALIGNMENTS[i].isDefault === true) {
+                    css = ALIGNMENTS[i].value + ':' + ALIGNMENTS[i].name + ';';
+                    form.one('.' + CSS.INPUTALIGNMENT).set('value', css);
+                }
+            }
+            // Remove the custom style option if this is a new image.
+            form.one('.' + CSS.INPUTALIGNMENT).getDOMNode().options.remove(ALIGNMENTS.length - 1);
             return;
         }
 
         if (properties.align) {
             form.one('.' + CSS.INPUTALIGNMENT).set('value', properties.align);
+            // Remove the custom style option if we have a standard alignment.
+            form.one('.' + CSS.INPUTALIGNMENT).getDOMNode().options.remove(ALIGNMENTS.length - 1);
+        } else {
+            form.one('.' + CSS.INPUTALIGNMENT).set('value', 'style:customstyle;');
+        }
+        if (properties.customstyle) {
+            form.one('.' + CSS.INPUTCUSTOMSTYLE).set('value', properties.customstyle);
         }
         if (properties.display) {
             img.setStyle('display', properties.display);
@@ -474,7 +536,7 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
                 alt :null,
                 width: null,
                 height: null,
-                align: null,
+                align: '',
                 display: 'inline',
                 presentation: false
             },
@@ -492,20 +554,34 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
             this._selectedImage = image;
 
             style = image.getAttribute('style');
-            width = parseInt(image.getAttribute('width'), 10);
-            height = parseInt(image.getAttribute('height'), 10);
+            properties.customstyle = style;
+            style = style.replace(/ /g, '');
+
+            width = image.getAttribute('width');
+            if (!width.match(REGEX.ISPERCENT)) {
+                width = parseInt(width, 10);
+            }
+            height = image.getAttribute('height');
+            if (!height.match(REGEX.ISPERCENT)) {
+                height = parseInt(height, 10);
+            }
 
-            if (width > 0) {
+            if (width !== 0) {
                 properties.width = width;
             }
-            if (height > 0) {
+            if (height !== 0) {
                 properties.height = height;
             }
             for (i in ALIGNMENTS) {
                 css = ALIGNMENTS[i].value + ':' + ALIGNMENTS[i].name + ';';
-                if (style.replace(' ', '').indexOf(css) !== -1) {
-                    properties.align = css;
-                    break;
+                if (style.indexOf(css) !== -1) {
+                    margin = 'margin:' + ALIGNMENTS[i].margin + ';';
+                    margin = margin.replace(/ /g, '');
+                    // Must match alignment and margins - otherwise custom style is selected.
+                    if (style.indexOf(margin) !== -1) {
+                        properties.align = css;
+                        break;
+                    }
                 }
             }
             properties.src = image.getAttribute('src');
@@ -549,8 +625,13 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
             width = form.one('.' + CSS.INPUTWIDTH).get('value'),
             height = form.one('.' + CSS.INPUTHEIGHT).get('value'),
             alignment = form.one('.' + CSS.INPUTALIGNMENT).get('value'),
+            margin = '',
             presentation = form.one('.' + CSS.IMAGEPRESENTATION).get('checked'),
+            constrain = form.one('.' + CSS.INPUTCONSTRAIN).get('checked'),
             imagehtml,
+            customstyle = '',
+            i,
+            classlist = [],
             host = this.get('host');
 
         e.preventDefault();
@@ -560,10 +641,6 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
             return;
         }
 
-        this.getDialogue({
-            focusAfterHide: null
-        }).hide();
-
         // Focus on the editor in preparation for inserting the image.
         host.focus();
         if (url !== '') {
@@ -572,6 +649,32 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
             } else {
                 host.setSelection(this._currentSelection);
             }
+
+            if (alignment === 'style:customstyle;') {
+                alignment = '';
+                customstyle = form.one('.' + CSS.INPUTCUSTOMSTYLE).get('value');
+            } else {
+                for (i in ALIGNMENTS) {
+                    css = ALIGNMENTS[i].value + ':' + ALIGNMENTS[i].name + ';';
+                    if (alignment === css) {
+                        margin = ' margin: ' + ALIGNMENTS[i].margin + ';';
+                    }
+                }
+            }
+
+            if (constrain) {
+                classlist.push(CSS.RESPONSIVE);
+            }
+
+            if (!width.match(REGEX.ISPERCENT) && isNaN(parseInt(width, 10))) {
+                form.one('.' + CSS.INPUTWIDTH).focus();
+                return;
+            }
+            if (!height.match(REGEX.ISPERCENT) && isNaN(parseInt(height, 10))) {
+                form.one('.' + CSS.INPUTHEIGHT).focus();
+                return;
+            }
+
             template = Y.Handlebars.compile(IMAGETEMPLATE);
             imagehtml = template({
                 url: url,
@@ -579,13 +682,21 @@ Y.namespace('M.atto_image').Button = Y.Base.create('button', Y.M.editor_atto.Edi
                 width: width,
                 height: height,
                 presentation: presentation,
-                alignment: alignment
+                alignment: alignment,
+                margin: margin,
+                customstyle: customstyle,
+                classlist: classlist.join(' ')
             });
 
             this.get('host').insertContentAtFocusPoint(imagehtml);
 
             this.markUpdated();
         }
+
+        this.getDialogue({
+            focusAfterHide: null
+        }).hide();
+
     },
 
     /**
index c416a6f..84be800 100644 (file)
@@ -155,7 +155,7 @@ div.editor_atto_content:hover .atto_control {
     display: block;
 }
 
-.yui3-menu-hidden {
+.editor_atto_menu.yui3-menu-hidden {
     display: none;
 }
 
index 5149d80..3c7dca6 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 f22d5ad..4e29469 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 e1cb432..4fd24e4 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 daa1661..33c2ba4 100644 (file)
@@ -600,6 +600,9 @@ EditorPluginButtons.prototype = {
             this.get('host').focus();
         }
 
+        // Save the selection.
+        this.get('host').saveSelection();
+
         // Ensure that we focus on this button next time.
         if (creatorButton) {
             this.get('host')._setTabFocus(creatorButton);
index 1910392..6b4645d 100644 (file)
@@ -401,7 +401,13 @@ class stored_file {
     * @return void
     */
     public function add_to_curl_request(&$curlrequest, $key) {
-        $curlrequest->_tmp_file_post_params[$key] = '@' . $this->get_content_file_location();
+        if (function_exists('curl_file_create')) {
+            // As of PHP 5.5, the usage of the @filename API for file uploading is deprecated.
+            $value = curl_file_create($this->get_content_file_location());
+        } else {
+            $value = '@' . $this->get_content_file_location();
+        }
+        $curlrequest->_tmp_file_post_params[$key] = $value;
     }
 
     /**
index b292d78..4ffa83c 100644 (file)
@@ -4138,9 +4138,9 @@ function truncate_userinfo(array $info) {
         'icq'         =>  15,
         'phone1'      =>  20,
         'phone2'      =>  20,
-        'institution' =>  40,
-        'department'  =>  30,
-        'address'     =>  70,
+        'institution' => 255,
+        'department'  => 255,
+        'address'     => 255,
         'city'        => 120,
         'country'     =>   2,
         'url'         => 255,
index 59a6d1a..3aae32f 100644 (file)
@@ -803,7 +803,6 @@ class moodle_page {
      * @return renderer_base
      */
     public function get_renderer($component, $subtype = null, $target = null) {
-        $target = null;
         if ($this->pagelayout === 'maintenance') {
             // If the page is using the maintenance layout then we're going to force target to maintenance.
             // This leads to a special core renderer that is designed to block access to API's that are likely unavailable for this
index ed350cd..4cb804e 100644 (file)
@@ -1261,7 +1261,7 @@ function disable_output_buffering() {
  */
 function redirect_if_major_upgrade_required() {
     global $CFG;
-    $lastmajordbchanges = 2014040408.00;
+    $lastmajordbchanges = 2014040800.00;
     if (empty($CFG->version) or (float)$CFG->version < $lastmajordbchanges or
             during_initial_install() or !empty($CFG->adminsetuppending)) {
         try {
index a798e20..8ba3a26 100644 (file)
@@ -1082,7 +1082,7 @@ CSS;
     public function test_css_chunking() {
         // Test with an even number of styles.
         $css = 'a{}b{}c{}d{}e{}f{}';
-        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
         $this->assertInternalType('array', $chunks);
         $this->assertCount(3, $chunks);
         $this->assertArrayHasKey(0, $chunks);
@@ -1094,7 +1094,7 @@ CSS;
 
         // Test with an odd number of styles.
         $css = 'a{}b{}c{}d{}e{}';
-        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
         $this->assertInternalType('array', $chunks);
         $this->assertCount(3, $chunks);
         $this->assertArrayHasKey(0, $chunks);
@@ -1104,21 +1104,9 @@ CSS;
         $this->assertSame('c{}d{}', $chunks[1]);
         $this->assertSame("@import url(styles.php?type=test&chunk=1);\n@import url(styles.php?type=test&chunk=2);\ne{}", $chunks[2]);
 
-        // Test buffering. Set a buffer that will reduce the effective sheet size back to two.
-        $css = 'a{}b{}c{}d{}e{}f{}';
-        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 6, 4);
-        $this->assertInternalType('array', $chunks);
-        $this->assertCount(3, $chunks);
-        $this->assertArrayHasKey(0, $chunks);
-        $this->assertArrayHasKey(1, $chunks);
-        $this->assertArrayHasKey(2, $chunks);
-        $this->assertSame('a{}b{}', $chunks[0]);
-        $this->assertSame('c{}d{}', $chunks[1]);
-        $this->assertSame("@import url(styles.php?type=test&chunk=1);\n@import url(styles.php?type=test&chunk=2);\ne{}f{}", $chunks[2]);
-
         // Test well placed commas.
         $css = 'a,b{}c,d{}e,f{}';
-        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
         $this->assertInternalType('array', $chunks);
         $this->assertCount(3, $chunks);
         $this->assertArrayHasKey(0, $chunks);
@@ -1130,56 +1118,117 @@ CSS;
 
         // Test unfortunately placed commas.
         $css = 'a{}b,c{color:red;}d{}e{}f{}';
-        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
         $this->assertInternalType('array', $chunks);
-        $this->assertCount(3, $chunks);
+        $this->assertCount(4, $chunks);
         $this->assertArrayHasKey(0, $chunks);
         $this->assertArrayHasKey(1, $chunks);
         $this->assertArrayHasKey(2, $chunks);
-        $this->assertSame('a{}b{color:red;}', $chunks[0]);
-        $this->assertSame('c{color:red;}d{}', $chunks[1]);
-        $this->assertSame("@import url(styles.php?type=test&chunk=1);\n@import url(styles.php?type=test&chunk=2);\ne{}f{}", $chunks[2]);
+        $this->assertArrayHasKey(3, $chunks);
+        $this->assertSame('a{}', $chunks[0]);
+        $this->assertSame('b,c{color:red;}', $chunks[1]);
+        $this->assertSame('d{}e{}', $chunks[2]);
+        $this->assertSame("@import url(styles.php?type=test&chunk=1);\n@import url(styles.php?type=test&chunk=2);\n@import url(styles.php?type=test&chunk=3);\nf{}", $chunks[3]);
 
         // Test unfortunate CSS.
         $css = 'a,b,c,d,e,f{color:red;}';
         $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
         $this->assertInternalType('array', $chunks);
-        $this->assertCount(3, $chunks);
+        $this->assertCount(1, $chunks);
         $this->assertArrayHasKey(0, $chunks);
-        $this->assertArrayHasKey(1, $chunks);
-        $this->assertArrayHasKey(2, $chunks);
-        $this->assertSame('a,b{color:red;}', $chunks[0]);
-        $this->assertSame('c,d{color:red;}', $chunks[1]);
-        $this->assertSame("@import url(styles.php?type=test&chunk=1);\n@import url(styles.php?type=test&chunk=2);\ne,f{color:red;}", $chunks[2]);
+        $this->assertSame('a,b,c,d,e,f{color:red;}', $chunks[0]);
+        $this->assertDebuggingCalled('Could not find a safe place to split at offset(s): 6. Those were ignored.');
 
         // Test to make sure invalid CSS isn't totally ruined.
         $css = 'a{},,,e{},';
-        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
         // Believe it or not we want to care what comes out here as this will be parsed correctly
         // by a browser.
         $this->assertInternalType('array', $chunks);
-        $this->assertCount(2, $chunks);
+        $this->assertCount(3, $chunks);
         $this->assertArrayHasKey(0, $chunks);
         $this->assertArrayHasKey(1, $chunks);
-        $this->assertSame('a{},{}', $chunks[0]);
-        $this->assertSame("@import url(styles.php?type=test&chunk=1);\n,e{}/** Error chunking CSS **/", $chunks[1]);
+        $this->assertArrayHasKey(2, $chunks);
+        $this->assertSame('a{}', $chunks[0]);
+        $this->assertSame(',,,e{}', $chunks[1]);
+        $this->assertSame("@import url(styles.php?type=test&chunk=1);\n@import url(styles.php?type=test&chunk=2);\n,", $chunks[2]);
+        $this->assertDebuggingCalled('Could not find a safe place to split at offset(s): 6. Those were ignored.');
 
         // Test utter crap CSS to make sure we don't loop to our deaths.
         $css = 'a,b,c,d,e,f';
-        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
         $this->assertInternalType('array', $chunks);
-        $this->assertCount(3, $chunks);
+        $this->assertCount(1, $chunks);
         $this->assertArrayHasKey(0, $chunks);
-        $this->assertArrayHasKey(1, $chunks);
-        $this->assertArrayHasKey(2, $chunks);
-        $this->assertSame('a,b/** Error chunking CSS **/', $chunks[0]);
-        $this->assertSame('c,d/** Error chunking CSS **/', $chunks[1]);
-        $this->assertSame("@import url(styles.php?type=test&chunk=1);\n@import url(styles.php?type=test&chunk=2);\ne,f", $chunks[2]);
+        $this->assertSame($css, $chunks[0]);
+        $this->assertDebuggingCalled('Could not find a safe place to split at offset(s): 6. Those were ignored.');
+
         // Test another death situation to make sure we're invincible.
         $css = 'a,,,,,e';
-        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2, 0);
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
         $this->assertInternalType('array', $chunks);
+        $this->assertDebuggingCalled('Could not find a safe place to split at offset(s): 4. Those were ignored.');
         // I don't care what the outcome is, I just want to make sure it doesn't die.
+
+        // Test media queries.
+        $css = '@media (min-width: 980px) { .a,.b{} }';
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
+        $this->assertCount(1, $chunks);
+        $this->assertSame('@media (min-width: 980px) { .a,.b{} }', $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);
+        $this->assertCount(2, $chunks);
+        $this->assertSame('a,b{ background-image: linear-gradient(to bottom, #ffffff, #cccccc);}', $chunks[0]);
+        $this->assertSame("@import url(styles.php?type=test&chunk=1);\nd,e{}", $chunks[1]);
+
+        // Test media queries with too many selectors.
+        $css = '@media (min-width: 980px) { a,b,c,d{} }';
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
+        $this->assertCount(1, $chunks);
+        $this->assertSame('@media (min-width: 980px) { a,b,c,d{} }', $chunks[0]);
+        $this->assertDebuggingCalled('Could not find a safe place to split at offset(s): 34. Those were ignored.');
+
+        // Complex test.
+        $css = '@media (a) {b{}} c{} d,e{} f,g,h{} i,j{x:a,b,c} k,l{} @media(x){l,m{ y: a,b,c}} n{}';
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 3);
+        $this->assertCount(6, $chunks);
+        $this->assertSame('@media (a) {b{}} c{}', $chunks[0]);
+        $this->assertSame(' d,e{}', $chunks[1]);
+        $this->assertSame(' f,g,h{}', $chunks[2]);
+        $this->assertSame(' i,j{x:a,b,c}', $chunks[3]);
+        $this->assertSame(' k,l{}', $chunks[4]);
+        $this->assertSame("@import url(styles.php?type=test&chunk=1);\n@import url(styles.php?type=test&chunk=2);\n@import url(styles.php?type=test&chunk=3);\n@import url(styles.php?type=test&chunk=4);\n@import url(styles.php?type=test&chunk=5);\n @media(x){l,m{ y: a,b,c}} n{}", $chunks[5]);
+
+        // Multiple offset errors.
+        $css = 'a,b,c{} d,e,f{}';
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
+        $this->assertCount(2, $chunks);
+        $this->assertSame('a,b,c{}', $chunks[0]);
+        $this->assertSame("@import url(styles.php?type=test&chunk=1);\n d,e,f{}", $chunks[1]);
+        $this->assertDebuggingCalled('Could not find a safe place to split at offset(s): 6, 14. Those were ignored.');
+
+        // Test the split according to IE.
+        $css = str_repeat('a{}', 4100);
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test');
+        $this->assertCount(2, $chunks);
+        $this->assertSame(str_repeat('a{}', 4095), $chunks[0]);
+        $this->assertSame("@import url(styles.php?type=test&chunk=1);\n" . str_repeat('a{}', 5), $chunks[1]);
+
+        // Test strip out comments.
+        $css = ".a {/** a\nb\nc */} /** a\nb\nc */ .b{} /** .c,.d{} */ e{}";
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
+        $this->assertCount(2, $chunks);
+        $this->assertSame('.a {}  .b{}', $chunks[0]);
+        $this->assertSame("@import url(styles.php?type=test&chunk=1);\n  e{}", $chunks[1]);
+
+        // Test something with unicode characters.
+        $css = 'a,b{} nav a:hover:after { content: "↓"; } b{ color:test;}';
+        $chunks = css_chunk_by_selector_count($css, 'styles.php?type=test', 2);
+        $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]);
     }
 
     /**
diff --git a/lib/tests/event_unknown_logged_test.php b/lib/tests/event_unknown_logged_test.php
new file mode 100644 (file)
index 0000000..7d07dce
--- /dev/null
@@ -0,0 +1,53 @@
+<?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/>.
+
+/**
+ * Tests for event manager, base event and observers.
+ *
+ * @package    core
+ * @category   phpunit
+ * @copyright  2014 Petr Skoda
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+require_once(__DIR__.'/fixtures/event_fixtures.php');
+
+class core_event_unknown_logged_testcase extends advanced_testcase {
+
+    public function test_restore_event() {
+        $event1 = \core_tests\event\unittest_executed::create(array('context' => context_system::instance(), 'other' => array('sample' => 1, 'xx' => 10)));
+        $data1 = $event1->get_data();
+
+        $data1['eventname'] = '\mod_xx\event\xx_yy';
+        $data1['component'] = 'mod_xx';
+        $data1['action'] = 'yy';
+        $data1['target'] = 'xx';
+        $extra1 = array('origin' => 'cli');
+
+        $event2 = \core\event\base::restore($data1, $extra1);
+        $data2 = $event2->get_data();
+        $extra2 = $event2->get_logextra();
+
+        $this->assertInstanceOf('core\event\unknown_logged', $event2);
+        $this->assertTrue($event2->is_triggered());
+        $this->assertTrue($event2->is_restored());
+        $this->assertNull($event2->get_url());
+        $this->assertEquals($data1, $data2);
+        $this->assertEquals($extra1, $extra2);
+    }
+}
\ No newline at end of file
index 6a23e95..0428744 100644 (file)
@@ -94,19 +94,19 @@ class core_eventslib_testcase extends advanced_testcase {
     }
 
     /**
-     * Tests events_trigger() function.
+     * Tests events_trigger_legacy() function.
      */
-    public function test_events_trigger__instant() {
-        $this->assertEquals(0, events_trigger('test_instant', 'ok'));
-        $this->assertEquals(0, events_trigger('test_instant', 'ok'));
+    public function test_events_trigger_legacy_instant() {
+        $this->assertEquals(0, events_trigger_legacy('test_instant', 'ok'));
+        $this->assertEquals(0, events_trigger_legacy('test_instant', 'ok'));
         $this->assertEquals(2, eventslib_sample_function_handler('status'));
     }
 
     /**
-     * Tests events_trigger() function.
+     * Tests events_trigger_legacy() function.
      */
     public function test_events_trigger__cron() {
-        $this->assertEquals(0, events_trigger('test_cron', 'ok'));
+        $this->assertEquals(0, events_trigger_legacy('test_cron', 'ok'));
         $this->assertEquals(0, eventslib_sample_handler_class::static_method('status'));
         events_cron('test_cron');
         $this->assertEquals(1, eventslib_sample_handler_class::static_method('status'));
@@ -116,21 +116,21 @@ class core_eventslib_testcase extends advanced_testcase {
      * Tests events_pending_count() function.
      */
     public function test_events_pending_count() {
-        events_trigger('test_cron', 'ok');
-        events_trigger('test_cron', 'ok');
+        events_trigger_legacy('test_cron', 'ok');
+        events_trigger_legacy('test_cron', 'ok');
         events_cron('test_cron');
         $this->assertEquals(0, events_pending_count('test_cron'), 'all messages should be already dequeued: %s');
     }
 
     /**
-     * Tests events_trigger() function when instant handler fails.
+     * Tests events_trigger_legacy() function when instant handler fails.
      */
     public function test_events_trigger__failed_instant() {
         global $CFG;
         $olddebug = $CFG->debug;
 
-        $this->assertEquals(1, events_trigger('test_instant', 'fail'), 'fail first event: %s');
-        $this->assertEquals(1, events_trigger('test_instant', 'ok'), 'this one should fail too: %s');
+        $this->assertEquals(1, events_trigger_legacy('test_instant', 'fail'), 'fail first event: %s');
+        $this->assertEquals(1, events_trigger_legacy('test_instant', 'ok'), 'this one should fail too: %s');
 
         $this->assertEquals(0, events_cron('test_instant'), 'all events should stay in queue: %s');
         $this->assertDebuggingCalled();
@@ -138,18 +138,25 @@ class core_eventslib_testcase extends advanced_testcase {
         $this->assertEquals(2, events_pending_count('test_instant'), 'two events should in queue: %s');
         $this->assertEquals(0, eventslib_sample_function_handler('status'), 'verify no event dispatched yet: %s');
         eventslib_sample_function_handler('ignorefail'); // Ignore "fail" eventdata from now on.
-        $this->assertEquals(1, events_trigger('test_instant', 'ok'), 'this one should go to queue directly: %s');
+        $this->assertEquals(1, events_trigger_legacy('test_instant', 'ok'), 'this one should go to queue directly: %s');
         $this->assertEquals(3, events_pending_count('test_instant'), 'three events should in queue: %s');
         $this->assertEquals(0, eventslib_sample_function_handler('status'), 'verify previous event was not dispatched: %s');
         $this->assertEquals(3, events_cron('test_instant'), 'all events should be dispatched: %s');
         $this->assertEquals(3, eventslib_sample_function_handler('status'), 'verify three events were dispatched: %s');
         $this->assertEquals(0, events_pending_count('test_instant'), 'no events should in queue: %s');
-        $this->assertEquals(0, events_trigger('test_instant', 'ok'), 'this event should be dispatched immediately: %s');
+        $this->assertEquals(0, events_trigger_legacy('test_instant', 'ok'), 'this event should be dispatched immediately: %s');
         $this->assertEquals(4, eventslib_sample_function_handler('status'), 'verify event was dispatched: %s');
         $this->assertEquals(0, events_pending_count('test_instant'), 'no events should in queue: %s');
     }
-}
 
+    /**
+     * Tests events_trigger() function.
+     */
+    public function test_events_trigger_debugging() {
+        $this->assertEquals(0, events_trigger('test_instant', 'ok'));
+        $this->assertDebuggingCalled();
+    }
+}
 
 /**
  * Test handler function.
index 866ac32..eb5a392 100644 (file)
@@ -284,6 +284,7 @@ class core_grades_external_testcase extends externallib_advanced_testcase {
             array(),
             array('hidden' => 1)
         );
+        $result = external_api::clean_returnvalue(core_grades_external::update_grades_returns(), $result);
         $this->assertTrue($result == GRADE_UPDATE_OK);
 
         // Check it's definitely hidden.
@@ -409,6 +410,7 @@ class core_grades_external_testcase extends externallib_advanced_testcase {
             array(),
             array('grademax' => $changedmax)
         );
+        $result = external_api::clean_returnvalue(core_grades_external::update_grades_returns(), $result);
         $this->assertTrue($result == GRADE_UPDATE_OK);
         $grades = grade_get_grades($course->id, 'mod', 'assign', $assignment->id);
         $this->assertTrue($grades->items[0]->grademax == $changedmax);
@@ -423,6 +425,7 @@ class core_grades_external_testcase extends externallib_advanced_testcase {
             0,
             array(array('studentid' => $student1->id, 'grade' => $student1grade))
         );
+        $result = external_api::clean_returnvalue(core_grades_external::update_grades_returns(), $result);
         $this->assertTrue($result == GRADE_UPDATE_OK);
         $grades = grade_get_grades($course->id, 'mod', 'assign', $assignment->id, array($student1->id));
         $this->assertTrue($grades->items[0]->grades[$student1->id]->grade == $student1grade);
@@ -441,6 +444,7 @@ class core_grades_external_testcase extends externallib_advanced_testcase {
                 array('studentid' => $student2->id, 'grade' => $student2grade)
             )
         );
+        $result = external_api::clean_returnvalue(core_grades_external::update_grades_returns(), $result);
         $this->assertTrue($result == GRADE_UPDATE_OK);
         $grades = grade_get_grades($course->id, 'mod', 'assign', $assignment->id, array($student1->id, $student2->id));
         $this->assertTrue($grades->items[0]->grades[$student1->id]->grade == $student1grade);
@@ -516,6 +520,7 @@ class core_grades_external_testcase extends externallib_advanced_testcase {
             array(),
             array('hidden' => 1)
         );
+        $result = external_api::clean_returnvalue(core_grades_external::update_grades_returns(), $result);
         $this->assertTrue($result == GRADE_UPDATE_OK);
         $grades = grade_get_grades($course->id, 'mod', 'assign', $assignment->id);
         $this->assertTrue($grades->items[0]->hidden == 1);
index 2e73ea2..176fd80 100644 (file)
@@ -2464,7 +2464,6 @@ class core_moodlelib_testcase extends advanced_testcase {
 
         $this->assertTimeCurrent($user->firstaccess);
         $this->assertTimeCurrent($user->lastaccess);
-        $this->assertTimeCurrent($user->timemodified);
 
         $this->assertTimeCurrent($USER->firstaccess);
         $this->assertTimeCurrent($USER->lastaccess);
index 611f44c..01e48c1 100644 (file)
@@ -2097,31 +2097,39 @@ function upgrade_grade_item_fix_sortorder() {
     // to do it more efficiently by doing a series of update statements rather than updating
     // every single grade item in affected courses.
 
-    $transaction = $DB->start_delegated_transaction();
-
-    $sql = "SELECT DISTINCT g1.id, g1.courseid, g1.sortorder
+    $sql = "SELECT DISTINCT g1.courseid
               FROM {grade_items} g1
               JOIN {grade_items} g2 ON g1.courseid = g2.courseid
              WHERE g1.sortorder = g2.sortorder AND g1.id != g2.id
-             ORDER BY g1.courseid ASC, g1.sortorder DESC, g1.id DESC";
-
-    // Get all duplicates in course order, highest sort order, and higest id first so that we can make space at the
-    // bottom higher end of the sort orders and work down by id.
-    $rs = $DB->get_recordset_sql($sql);
+             ORDER BY g1.courseid ASC";
+    foreach ($DB->get_fieldset_sql($sql) as $courseid) {
+        $transaction = $DB->start_delegated_transaction();
+        $items = $DB->get_records('grade_items', array('courseid' => $courseid), '', 'id, sortorder, sortorder AS oldsort');
+
+        // Get all duplicates in course order, highest sort order, and higest id first so that we can make space at the
+        // bottom higher end of the sort orders and work down by id.
+        $sql = "SELECT DISTINCT g1.id, g1.sortorder
+                FROM {grade_items} g1
+                JOIN {grade_items} g2 ON g1.courseid = g2.courseid
+                WHERE g1.sortorder = g2.sortorder AND g1.id != g2.id AND g1.courseid = :courseid
+                ORDER BY g1.sortorder DESC, g1.id DESC";
+
+        // This is the O(N*N) like the database version we're replacing, but at least the constants are a billion times smaller...
+        foreach ($DB->get_records_sql($sql, array('courseid' => $courseid)) as $duplicate) {
+            foreach ($items as $item) {
+                if ($item->sortorder > $duplicate->sortorder || ($item->sortorder == $duplicate->sortorder && $item->id > $duplicate->id)) {
+                    $item->sortorder += 1;
+                }
+            }
+        }
+        foreach ($items as $item) {
+            if ($item->sortorder != $item->oldsort) {
+                $DB->update_record('grade_items', array('id' => $item->id, 'sortorder' => $item->sortorder));
+            }
+        }
 
-    foreach($rs as $duplicate) {
-        $DB->execute("UPDATE {grade_items}
-                         SET sortorder = sortorder + 1
-                       WHERE courseid = :courseid AND
-                       (sortorder > :sortorder OR (sortorder = :sortorder2 AND id > :id))",
-            array('courseid' => $duplicate->courseid,
-                'sortorder' => $duplicate->sortorder,
-                'sortorder2' => $duplicate->sortorder,
-                'id' => $duplicate->id));
+        $transaction->allow_commit();
     }
-    $rs->close();
-
-    $transaction->allow_commit();
 }
 
 /**
index 3e180e3..f1bc1d2 100644 (file)
@@ -30,6 +30,7 @@ defined('MOODLE_INTERNAL') || die();
  * mod_assign all submissions downloaded event class.
  *
  * @package    mod_assign
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 258aa9e..b639423 100644 (file)
@@ -36,6 +36,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    mod_assign
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index a7c20ec..3b26e51 100644 (file)
@@ -30,6 +30,7 @@ defined('MOODLE_INTERNAL') || die();
  * mod_assign extension granted event class.
  *
  * @package    mod_assign
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 1bc307a..ad8948f 100644 (file)
@@ -30,6 +30,7 @@ defined('MOODLE_INTERNAL') || die();
  * mod_assign identities revealed event class.
  *
  * @package    mod_assign
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index ba36181..362fb3f 100644 (file)
@@ -36,6 +36,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    mod_assign
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index ea92ec3..d0a0811 100644 (file)
@@ -30,6 +30,7 @@ defined('MOODLE_INTERNAL') || die();
  * mod_assign statement accepted event class.
  *
  * @package    mod_assign
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 22df013..ad67856 100644 (file)
@@ -37,6 +37,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    mod_assign
+ * @since      Moodle 2.7
  * @copyright  2014 Adrian Greeve <adrian@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index e25a3c4..04e4b1c 100644 (file)
@@ -30,6 +30,7 @@ defined('MOODLE_INTERNAL') || die();
  * mod_assign submission duplicated event class.
  *
  * @package    mod_assign
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index ff82bd3..3ac1e46 100644 (file)
@@ -30,6 +30,7 @@ defined('MOODLE_INTERNAL') || die();
  * mod_assign submission graded event class.
  *
  * @package    mod_assign
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 5327faf..5275478 100644 (file)
@@ -30,6 +30,7 @@ defined('MOODLE_INTERNAL') || die();
  * mod_assign submission locked event class.
  *
  * @package    mod_assign
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index e998ef2..6941310 100644 (file)
@@ -36,6 +36,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    mod_assign
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 5e97042..5105e35 100644 (file)
@@ -30,6 +30,7 @@ defined('MOODLE_INTERNAL') || die();
  * mod_assign submission unlocked event class.
  *
  * @package    mod_assign
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 69120ab..d2cebf4 100644 (file)
@@ -37,6 +37,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    mod_assign
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 683b140..d1cb048 100644 (file)
@@ -36,6 +36,7 @@ defined('MOODLE_INTERNAL') || die();
  * }
  *
  * @package    mod_assign
+ * @since      Moodle 2.6
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 240cc6a..d6dca2c 100644 (file)
@@ -827,6 +827,11 @@ function assign_scale_used_anywhere($scaleid) {
 /**
  * List the actions that correspond to a view of this module.
  * This is used by the participation report.
+ *
+ * Note: This is not used by new logging system. Event with
+ *       crud = 'r' and edulevel = LEVEL_PARTICIPATING will
+ *       be considered as view action.
+ *
  * @return array
  */
 function assign_get_view_actions() {
@@ -836,6 +841,11 @@ function assign_get_view_actions() {
 /**
  * List the actions that correspond to a post of this module.
  * This is used by the participation report.
+ *
+ * Note: This is not used by new logging system. Event with
+ *       crud = ('c' || 'u' || 'd') and edulevel = LEVEL_PARTICIPATING
+ *       will be considered as post action.
+ *
  * @return array
  */
 function assign_get_post_actions() {
index 0339217..73a97a0 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * assignsubmission_comments comment created event.
  *
  * @package    assignsubmission_comments
+ * @since      Moodle 2.7
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
index 2b11fa3..ed65072 100644 (file)
@@ -29,6 +29,7 @@ defined('MOODLE_INTERNAL') || die();
  * assignsubmission_comments comment deleted event.
  *
  * @package    assignsubmission_comments
+ * @since      Moodle 2.7
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */