Merge branch 'MDL-42212-master' of git://github.com/FMCorz/moodle
authorSam Hemelryk <sam@moodle.com>
Sun, 5 Jan 2014 21:30:31 +0000 (10:30 +1300)
committerSam Hemelryk <sam@moodle.com>
Sun, 5 Jan 2014 21:30:31 +0000 (10:30 +1300)
285 files changed:
admin/cli/install.php
admin/cli/install_database.php
admin/environment.xml
admin/index.php
admin/tool/behat/cli/util.php
admin/tool/behat/tests/manager_test.php [moved from admin/tool/behat/tests/tool_behat_test.php with 95% similarity]
auth/mnet/auth.php
backup/cc/entities.class.php
badges/criteria/award_criteria.php
badges/criteria/award_criteria_activity.php
badges/criteria/award_criteria_course.php
badges/criteria/award_criteria_courseset.php
badges/criteria/award_criteria_manual.php
badges/criteria/award_criteria_overall.php
badges/criteria/award_criteria_profile.php
badges/tests/badgeslib_test.php
badges/upgrade.txt [new file with mode: 0644]
blocks/community/yui/comments/comments.js
blocks/community/yui/imagegallery/imagegallery.js
blocks/course_list/block_course_list.php
blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-debug.js
blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-min.js
blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation.js
blocks/navigation/yui/src/navigation/js/navigation.js
cache/classes/definition.php
cache/stores/memcache/lib.php
config-dist.php
course/dndupload.js
course/dnduploadlib.php
course/lib.php
course/tests/behat/activities_edit_with_block_dock.feature [new file with mode: 0644]
course/tests/behat/behat_course.php
course/view.php
course/yui/build/moodle-course-modchooser/moodle-course-modchooser-debug.js [new file with mode: 0644]
course/yui/build/moodle-course-modchooser/moodle-course-modchooser-min.js [new file with mode: 0644]
course/yui/build/moodle-course-modchooser/moodle-course-modchooser.js [new file with mode: 0644]
course/yui/modchooser/modchooser.js [deleted file]
course/yui/src/modchooser/build.json [new file with mode: 0644]
course/yui/src/modchooser/js/modchooser.js [new file with mode: 0644]
course/yui/src/modchooser/meta/modchooser.json [new file with mode: 0644]
enrol/manual/yui/quickenrolment/quickenrolment.js
enrol/yui/rolemanager/rolemanager.js
filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-debug.js
filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-min.js
filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker.js
filter/glossary/yui/src/autolinker/js/autolinker.js
filter/urltolink/filter.php
filter/urltolink/tests/filter_test.php
install.php
install/lang/it/error.php
install/lang/zh_tw/error.php
lang/en/moodle.php
lib/accesslib.php
lib/adodb/adodb.inc.php
lib/adodb/readme_moodle.txt
lib/ajax/ajaxlib.php
lib/ajax/getsiteadminbranch.php
lib/badgeslib.php
lib/behat/classes/behat_command.php
lib/behat/classes/behat_config_manager.php
lib/behat/classes/util.php
lib/behat/lib.php
lib/classes/event/assessable_uploaded.php
lib/classes/event/blog_association_created.php
lib/classes/event/blog_entries_viewed.php
lib/classes/event/comment_created.php
lib/classes/event/comment_deleted.php
lib/classes/event/content_viewed.php
lib/classes/event/course_category_deleted.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_created.php
lib/classes/event/course_module_deleted.php
lib/classes/event/course_module_updated.php
lib/classes/event/course_reset_ended.php
lib/classes/event/course_reset_started.php
lib/classes/event/course_restored.php
lib/classes/event/course_section_updated.php
lib/classes/event/course_updated.php
lib/classes/event/group_member_added.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_assigned.php
lib/classes/event/role_deleted.php
lib/classes/event/role_unassigned.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_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_profile_viewed.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_token_created.php
lib/cronlib.php
lib/ddl/tests/ddl_test.php
lib/dml/moodle_database.php
lib/dml/moodle_temptables.php
lib/dml/mssql_native_moodle_database.php
lib/dml/mysqli_native_moodle_database.php
lib/dml/oci_native_moodle_database.php
lib/dml/pdo_moodle_database.php
lib/dml/pgsql_native_moodle_database.php
lib/dml/pgsql_native_moodle_temptables.php
lib/dml/sqlsrv_native_moodle_database.php
lib/dml/tests/dml_test.php
lib/editor/tinymce/plugins/managefiles/lib.php
lib/form/url.php
lib/grade/grade_category.php
lib/grade/tests/grade_category_test.php
lib/javascript-static.js
lib/medialib.php
lib/moodlelib.php
lib/outputrequirementslib.php
lib/setup.php
lib/statslib.php
lib/testing/classes/util.php
lib/testing/lib.php
lib/tests/accesslib_test.php
lib/tests/ajaxlib_test.php [new file with mode: 0644]
lib/tests/behat/behat_hooks.php
lib/thirdpartylibs.xml
lib/upgrade.txt
lib/yui/build/moodle-core-actionmenu/moodle-core-actionmenu-debug.js
lib/yui/build/moodle-core-actionmenu/moodle-core-actionmenu-min.js
lib/yui/build/moodle-core-actionmenu/moodle-core-actionmenu.js
lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue-debug.js
lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue-min.js
lib/yui/build/moodle-core-chooserdialogue/moodle-core-chooserdialogue.js
lib/yui/build/moodle-core-formchangechecker/moodle-core-formchangechecker-debug.js
lib/yui/build/moodle-core-formchangechecker/moodle-core-formchangechecker-min.js
lib/yui/build/moodle-core-formchangechecker/moodle-core-formchangechecker.js
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-debug.js
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue-min.js
lib/yui/build/moodle-core-notification-dialogue/moodle-core-notification-dialogue.js
lib/yui/build/moodle-core-tooltip/moodle-core-tooltip-debug.js
lib/yui/build/moodle-core-tooltip/moodle-core-tooltip-min.js
lib/yui/build/moodle-core-tooltip/moodle-core-tooltip.js
lib/yui/src/actionmenu/js/actionmenu.js
lib/yui/src/chooserdialogue/js/chooserdialogue.js
lib/yui/src/formchangechecker/js/formchangechecker.js
lib/yui/src/notification/js/dialogue.js
lib/yui/src/tooltip/js/tooltip.js
lib/yuilib/gallery/gallery-sm-treeview-sortable/gallery-sm-treeview-sortable-debug.js [moved from mod/scorm/yui/src/treeview/js/gallery-sm-treeview-sortable-debug.js with 89% similarity]
lib/yuilib/gallery/gallery-sm-treeview-sortable/gallery-sm-treeview-sortable-min.js [new file with mode: 0644]
lib/yuilib/gallery/gallery-sm-treeview-sortable/gallery-sm-treeview-sortable.js [new file with mode: 0644]
lib/yuilib/gallery/gallery-sm-treeview-templates/gallery-sm-treeview-templates-debug.js [new file with mode: 0644]
lib/yuilib/gallery/gallery-sm-treeview-templates/gallery-sm-treeview-templates-min.js [new file with mode: 0644]
lib/yuilib/gallery/gallery-sm-treeview-templates/gallery-sm-treeview-templates.js [new file with mode: 0644]
lib/yuilib/gallery/gallery-sm-treeview/assets/gallery-sm-treeview-core.css [moved from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/moodle-mod_scorm-treeview-core.css with 100% similarity]
lib/yuilib/gallery/gallery-sm-treeview/assets/skins/sam/folder.png [moved from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/folder.png with 100% similarity]
lib/yuilib/gallery/gallery-sm-treeview/assets/skins/sam/folder@2x.png [moved from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/folder@2x.png with 100% similarity]
lib/yuilib/gallery/gallery-sm-treeview/assets/skins/sam/gallery-sm-treeview-skin.css [moved from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/moodle-mod_scorm-treeview-skin.css with 100% similarity]
lib/yuilib/gallery/gallery-sm-treeview/assets/skins/sam/gallery-sm-treeview.css [moved from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/moodle-mod_scorm-treeview.css with 100% similarity]
lib/yuilib/gallery/gallery-sm-treeview/assets/skins/sam/item.png [moved from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/item.png with 100% similarity]
lib/yuilib/gallery/gallery-sm-treeview/assets/skins/sam/item@2x.png [moved from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/assets/skins/sam/item@2x.png with 100% similarity]
lib/yuilib/gallery/gallery-sm-treeview/gallery-sm-treeview-debug.js [moved from mod/scorm/yui/src/treeview/js/gallery-sm-treeview-debug.js with 95% similarity]
lib/yuilib/gallery/gallery-sm-treeview/gallery-sm-treeview-min.js [new file with mode: 0644]
lib/yuilib/gallery/gallery-sm-treeview/gallery-sm-treeview.js [moved from mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/moodle-mod_scorm-treeview-sortable-debug.js with 94% similarity]
lib/yuilib/readme_moodle.txt
mod/assign/classes/event/assessable_submitted.php
mod/assign/classes/event/marker_updated.php
mod/assign/classes/event/submission_status_updated.php
mod/assign/classes/event/workflow_state_updated.php
mod/assign/feedback/comments/lang/en/assignfeedback_comments.php
mod/assign/feedback/comments/locallib.php
mod/assign/feedback/comments/settings.php
mod/assign/feedback/comments/version.php
mod/assign/feedback/editpdf/classes/pdf.php
mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-debug.js
mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor-min.js
mod/assign/feedback/editpdf/yui/build/moodle-assignfeedback_editpdf-editor/moodle-assignfeedback_editpdf-editor.js
mod/assign/feedback/editpdf/yui/src/editor/js/commentsearch.js
mod/assign/feedback/editpdf/yui/src/editor/js/dropdown.js
mod/assign/locallib.php
mod/assign/renderable.php
mod/assign/renderer.php
mod/assign/submission/file/classes/event/assessable_uploaded.php
mod/assign/submission/onlinetext/classes/event/assessable_uploaded.php
mod/assign/submission/onlinetext/locallib.php
mod/assign/submission/onlinetext/tests/events_test.php
mod/assign/tests/behat/allow_another_attempt.feature [new file with mode: 0644]
mod/assign/tests/behat/comment_inline.feature [new file with mode: 0644]
mod/assign/tests/behat/edit_previous_feedback.feature [new file with mode: 0644]
mod/assign/tests/locallib_test.php
mod/assign/upgrade.txt
mod/assign/version.php
mod/assignment/lib.php
mod/assignment/type/online/classes/event/assessable_uploaded.php
mod/assignment/type/upload/assignment.class.php
mod/assignment/type/upload/classes/event/assessable_submitted.php
mod/assignment/type/upload/classes/event/assessable_uploaded.php
mod/assignment/type/uploadsingle/assignment.class.php
mod/assignment/view.php
mod/book/backup/moodle1/lib.php
mod/chat/classes/event/sessions_viewed.php
mod/choice/classes/event/answer_submitted.php
mod/choice/classes/event/answer_updated.php
mod/choice/classes/event/report_viewed.php
mod/data/field/url/field.class.php
mod/feedback/classes/event/course_module_viewed.php
mod/feedback/classes/event/response_deleted.php
mod/feedback/classes/event/response_submitted.php
mod/forum/classes/event/assessable_uploaded.php
mod/lti/classes/event/unknown_service_api_called.php
mod/quiz/classes/event/attempt_abandoned.php
mod/quiz/classes/event/attempt_becameoverdue.php
mod/quiz/classes/event/attempt_submitted.php
mod/scorm/module.js
mod/scorm/tests/behat/add_scorm.feature
mod/scorm/thirdpartylibs.xml [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/moodle-mod_scorm-treeview-sortable-min.js [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview-sortable/moodle-mod_scorm-treeview-sortable.js [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/moodle-mod_scorm-treeview-core.css [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/folder.png [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/folder@2x.png [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/item.png [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/item@2x.png [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/moodle-mod_scorm-treeview-skin.css [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/assets/skins/sam/moodle-mod_scorm-treeview.css [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/moodle-mod_scorm-treeview-debug.js [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/moodle-mod_scorm-treeview-min.js [deleted file]
mod/scorm/yui/build/moodle-mod_scorm-treeview/moodle-mod_scorm-treeview.js [deleted file]
mod/scorm/yui/src/treeview/assets/moodle-mod_scorm-treeview-core.css [deleted file]
mod/scorm/yui/src/treeview/assets/skins/sam/folder.png [deleted file]
mod/scorm/yui/src/treeview/assets/skins/sam/folder@2x.png [deleted file]
mod/scorm/yui/src/treeview/assets/skins/sam/item.png [deleted file]
mod/scorm/yui/src/treeview/assets/skins/sam/item@2x.png [deleted file]
mod/scorm/yui/src/treeview/assets/skins/sam/moodle-mod_scorm-treeview-skin.css [deleted file]
mod/scorm/yui/src/treeview/assets/skins/sam/moodle-mod_scorm-treeview.css [deleted file]
mod/scorm/yui/src/treeview/build.json [deleted file]
mod/scorm/yui/src/treeview/js/treeview-sortable.js [deleted file]
mod/scorm/yui/src/treeview/js/treeview.js [deleted file]
mod/scorm/yui/src/treeview/meta/sm-treeview.json [deleted file]
mod/scorm/yui/src/treeview/readme_moodle.txt [deleted file]
mod/url/classes/event/course_module_instance_list_viewed.php [moved from install/lang/es_ar/langconfig.php with 56% similarity]
mod/url/classes/event/course_module_viewed.php [moved from install/lang/es_es/langconfig.php with 55% similarity]
mod/url/index.php
mod/url/view.php
mod/wiki/classes/event/comment_created.php
mod/wiki/classes/event/comment_deleted.php
mod/wiki/classes/event/page_deleted.php
mod/wiki/classes/event/page_diff_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/tests/events_test.php
mod/workshop/classes/event/assessable_uploaded.php
portfolio/googledocs/lib.php
report/log/classes/event/content_viewed.php
report/loglive/classes/event/content_viewed.php
report/outline/classes/event/content_viewed.php
report/participation/classes/event/content_viewed.php
report/stats/classes/event/content_viewed.php
repository/dropbox/lib.php
repository/filepicker.js
repository/repository_ajax.php
theme/base/style/core.css
theme/base/style/course.css
theme/bootstrapbase/layout/columns1.php
theme/bootstrapbase/layout/columns2.php
theme/bootstrapbase/layout/columns3.php
theme/bootstrapbase/layout/popup.php
theme/bootstrapbase/less/moodle/core.less
theme/bootstrapbase/less/moodle/course.less
theme/bootstrapbase/less/moodle/undo.less
theme/bootstrapbase/renderers/core_renderer.php
theme/bootstrapbase/style/moodle.css
theme/clean/layout/columns1.php
theme/clean/layout/columns2.php
theme/clean/layout/columns3.php
theme/yui_combo.php
theme/yui_image.php
user/index.php
version.php

index a6c3873..df61269 100644 (file)
@@ -142,10 +142,10 @@ define('PHPUNIT_TEST', false);
 define('IGNORE_COMPONENT_CACHE', true);
 
 // Check that PHP is of a sufficient version
-if (version_compare(phpversion(), "5.3.3") < 0) {
+if (version_compare(phpversion(), "5.4.4") < 0) {
     $phpversion = phpversion();
     // do NOT localise - lang strings would not work here and we CAN NOT move it after installib
-    fwrite(STDERR, "Moodle 2.5 or later requires at least PHP 5.3.3 (currently using version $phpversion).\n");
+    fwrite(STDERR, "Moodle 2.7 or later requires at least PHP 5.4.4 (currently using version $phpversion).\n");
     fwrite(STDERR, "Please upgrade your server software or install older Moodle version.\n");
     exit(1);
 }
index 3ab6279..91ac890 100644 (file)
@@ -62,10 +62,10 @@ Example:
 ";
 
 // Check that PHP is of a sufficient version
-if (version_compare(phpversion(), "5.3.3") < 0) {
+if (version_compare(phpversion(), "5.4.4") < 0) {
     $phpversion = phpversion();
     // do NOT localise - lang strings would not work here and we CAN NOT move it after installib
-    fwrite(STDERR, "Moodle 2.5 or later requires at least PHP 5.3.3 (currently using version $phpversion).\n");
+    fwrite(STDERR, "Moodle 2.7 or later requires at least PHP 5.4.4 (currently using version $phpversion).\n");
     fwrite(STDERR, "Please upgrade your server software or install older Moodle version.\n");
     exit(1);
 }
index 1e937cd..4edfcd1 100644 (file)
       </PHP_SETTING>
     </PHP_SETTINGS>
   </MOODLE>
+  <MOODLE version="2.7" requires="2.2">
+    <UNICODE level="required">
+      <FEEDBACK>
+        <ON_ERROR message="unicoderequired" />
+      </FEEDBACK>
+    </UNICODE>
+    <DATABASE level="required">
+      <VENDOR name="mariadb" version="5.5.31" />
+      <VENDOR name="mysql" version="5.5.31" />
+      <VENDOR name="postgres" version="9.1" />
+      <VENDOR name="mssql" version="10.0" />
+      <VENDOR name="oracle" version="10.2" />
+    </DATABASE>
+    <PHP version="5.4.4" level="required">
+    </PHP>
+    <PCREUNICODE level="optional">
+      <FEEDBACK>
+        <ON_CHECK message="pcreunicodewarning" />
+      </FEEDBACK>
+    </PCREUNICODE>
+    <PHP_EXTENSIONS>
+      <PHP_EXTENSION name="iconv" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="iconvrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="mbstring" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="mbstringrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="curl" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="curlrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="openssl" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="opensslrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="tokenizer" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="tokenizerrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="xmlrpc" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="xmlrpcrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="soap" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="soaprecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="ctype" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="ctyperequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="zip" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="ziprequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="zlib" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="gd" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="gdrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="simplexml" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="simplexmlrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="spl" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="splrequired" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="pcre" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="dom" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="xml" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="intl" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="intlrecommended" />
+        </FEEDBACK>
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="json" level="required">
+      </PHP_EXTENSION>
+      <PHP_EXTENSION name="hash" level="required"/>
+    </PHP_EXTENSIONS>
+    <PHP_SETTINGS>
+      <PHP_SETTING name="memory_limit" value="96M" level="required">
+        <FEEDBACK>
+          <ON_ERROR message="settingmemorylimit" />
+        </FEEDBACK>
+      </PHP_SETTING>
+      <PHP_SETTING name="file_uploads" value="1" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="settingfileuploads" />
+        </FEEDBACK>
+      </PHP_SETTING>
+      <PHP_SETTING name="opcache.enable" value="1" level="optional">
+        <FEEDBACK>
+          <ON_CHECK message="opcacherecommended" />
+        </FEEDBACK>
+      </PHP_SETTING>
+    </PHP_SETTINGS>
+  </MOODLE>
 </COMPATIBILITY_MATRIX>
index a07104c..e42687a 100644 (file)
@@ -30,10 +30,10 @@ if (!file_exists('../config.php')) {
 }
 
 // Check that PHP is of a sufficient version as soon as possible
-if (version_compare(phpversion(), '5.3.3') < 0) {
+if (version_compare(phpversion(), '5.4.4') < 0) {
     $phpversion = phpversion();
     // do NOT localise - lang strings would not work here and we CAN NOT move it to later place
-    echo "Moodle 2.5 or later requires at least PHP 5.3.3 (currently using version $phpversion).<br />";
+    echo "Moodle 2.7 or later requires at least PHP 5.4.4 (currently using version $phpversion).<br />";
     echo "Please upgrade your server software or install older Moodle version.";
     die();
 }
index 28c933a..790406f 100644 (file)
@@ -78,85 +78,29 @@ if (!empty($options['help'])) {
     exit(0);
 }
 
-
-// Checking $CFG->behat_* vars and values.
+// Describe this script.
 define('BEHAT_UTIL', true);
 define('CLI_SCRIPT', true);
-define('ABORT_AFTER_CONFIG', true);
 define('NO_OUTPUT_BUFFERING', true);
 define('IGNORE_COMPONENT_CACHE', true);
 
-error_reporting(E_ALL | E_STRICT);
-ini_set('display_errors', '1');
-ini_set('log_errors', '1');
-
-// Getting $CFG data.
+// Only load CFG from config.php, stop ASAP in lib/setup.php.
+define('ABORT_AFTER_CONFIG', true);
 require_once(__DIR__ . '/../../../../config.php');
 
-// When we use the utilities we don't know how the site
-// will be accessed, so if neither $CFG->behat_switchcompletely or
-// $CFG->behat_wwwroot are set we must think that the site will
-// be accessed using the built-in server which is set by default
-// to localhost:8000. We need to do this to prevent uses of the production
-// wwwroot when the site is being installed / dropped...
-$CFG->behat_wwwroot = behat_get_wwwroot();
-
-// Checking the integrity of the provided $CFG->behat_* vars
-// to prevent conflicts with production and phpunit environments.
-behat_check_config_vars();
-
-// Create behat_dataroot if it doesn't exists.
-if (!file_exists($CFG->behat_dataroot)) {
-    if (!mkdir($CFG->behat_dataroot, $CFG->directorypermissions)) {
-        behat_error(BEHAT_EXITCODE_PERMISSIONS, '$CFG->behat_dataroot directory can not be created');
-    }
-}
-if (!is_dir($CFG->behat_dataroot) || !is_writable($CFG->behat_dataroot)) {
-    behat_error(BEHAT_EXITCODE_PERMISSIONS, '$CFG->behat_dataroot directory has no permissions or is not a directory');
-}
-
-// Check that the directory does not contains other things.
-if (!file_exists("$CFG->behat_dataroot/behattestdir.txt")) {
-    if ($dh = opendir($CFG->behat_dataroot)) {
-        while (($file = readdir($dh)) !== false) {
-            if ($file === 'behat' or $file === '.' or $file === '..' or $file === '.DS_Store') {
-                continue;
-            }
-            behat_error(BEHAT_EXITCODE_CONFIG, '$CFG->behat_dataroot directory is not empty, ensure this is the directory where you want to install behat test dataroot');
-        }
-        closedir($dh);
-        unset($dh);
-        unset($file);
-    }
-
-    // Now we create dataroot directory structure for behat tests.
-    testing_initdataroot($CFG->behat_dataroot, 'behat');
-}
-
-// Overrides vars with behat-test ones.
-$vars = array('wwwroot', 'prefix', 'dataroot');
-foreach ($vars as $var) {
-    $CFG->{$var} = $CFG->{'behat_' . $var};
-}
-
-// Clean $CFG extra values before performing any action.
-behat_clean_init_config();
-
-$CFG->noemailever = true;
-$CFG->passwordsaltmain = 'moodle';
-
-$CFG->themerev = 1;
-$CFG->jsrev = 1;
-
-// Unset cache and temp directories to reset them again with the new $CFG->dataroot.
-unset($CFG->cachedir);
-unset($CFG->localcachedir);
-unset($CFG->tempdir);
+// Remove error handling overrides done in config.php.
+$CFG->debug = (E_ALL | E_STRICT);
+$CFG->debugdisplay = 1;
+error_reporting($CFG->debug);
+ini_set('display_errors', '1');
+ini_set('log_errors', '1');
 
-// Continues setup.
+// Finish moodle init.
 define('ABORT_AFTER_CONFIG_CANCEL', true);
 require("$CFG->dirroot/lib/setup.php");
 
+raise_memory_limit(MEMORY_HUGE);
+
 require_once($CFG->libdir.'/adminlib.php');
 require_once($CFG->libdir.'/upgradelib.php');
 require_once($CFG->libdir.'/clilib.php');
@@ -185,7 +129,7 @@ if ($options['install']) {
     behat_util::start_test_mode();
     $runtestscommand = behat_command::get_behat_command() . ' --config '
         . $CFG->behat_dataroot . DIRECTORY_SEPARATOR . 'behat' . DIRECTORY_SEPARATOR . 'behat.yml';
-    mtrace("Acceptance tests environment enabled, to run the tests use:\n " . $runtestscommand);
+    mtrace("Acceptance tests environment enabled on $CFG->behat_wwwroot, to run the tests use:\n " . $runtestscommand);
 } else if ($options['disable']) {
     behat_util::stop_test_mode();
     mtrace("Acceptance tests environment disabled");
similarity index 95%
rename from admin/tool/behat/tests/tool_behat_test.php
rename to admin/tool/behat/tests/manager_test.php
index 09db5e6..1dc44ef 100644 (file)
@@ -15,7 +15,7 @@
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Unit tests for admin/tool/behat.
+ * Unit tests for behat manager.
  *
  * @package   tool_behat
  * @copyright  2012 David Monllaó
@@ -30,45 +30,13 @@ require_once($CFG->libdir . '/behat/classes/util.php');
 require_once($CFG->libdir . '/behat/classes/behat_config_manager.php');
 
 /**
- * Allows access to internal methods without exposing them.
- *
- * @package    tool_behat
- * @copyright  2012 David Monllaó
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
- */
-class testable_behat_config_manager extends behat_config_manager {
-
-    /**
-     * Allow access to protected method
-     * @see parent::merge_config()
-     * @param mixed $config
-     * @param mixed $localconfig
-     * @return mixed
-     */
-    public static function merge_config($config, $localconfig) {
-        return parent::merge_config($config, $localconfig);
-    }
-
-    /**
-     * Allow access to protected method
-     * @see parent::get_config_file_contents()
-     * @param array $features
-     * @param array $stepsdefinitions
-     * @return string
-     */
-    public static function get_config_file_contents($features, $stepsdefinitions) {
-        return parent::get_config_file_contents($features, $stepsdefinitions);
-    }
-}
-
-/**
- * Tool behat tests.
+ * Behat manager tests.
  *
  * @package    tool_behat
  * @copyright  2012 David Monllaó
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-class tool_behat_testcase extends advanced_testcase {
+class tool_behat_manager_testcase extends advanced_testcase {
 
     /**
      * behat_config_manager tests.
@@ -103,7 +71,7 @@ class tool_behat_testcase extends advanced_testcase {
 
         $array = testable_behat_config_manager::merge_config($array1, $array2);
 
-        // Overriddes are applied.
+        // Overrides are applied.
         $this->assertEquals('OVERRIDDEN1', $array['simple']);
         $this->assertEquals('OVERRIDDEN2', $array['array']['one']);
 
@@ -150,10 +118,8 @@ class tool_behat_testcase extends advanced_testcase {
             $this->markTestSkipped('Behat not installed.');
         }
 
-        // It is possible that it has no value.
-        if (empty($CFG->behat_wwwroot)) {
-            $CFG->behat_wwwroot = behat_get_wwwroot();
-        }
+        // Add some fake test url.
+        $CFG->behat_wwwroot = 'http://example.com/behat';
 
         // To avoid user value at config.php level.
         unset($CFG->behat_config);
@@ -194,3 +160,34 @@ class tool_behat_testcase extends advanced_testcase {
 
 }
 
+/**
+ * Allows access to internal methods without exposing them.
+ *
+ * @package    tool_behat
+ * @copyright  2012 David Monllaó
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class testable_behat_config_manager extends behat_config_manager {
+
+    /**
+     * Allow access to protected method
+     * @see parent::merge_config()
+     * @param mixed $config
+     * @param mixed $localconfig
+     * @return mixed
+     */
+    public static function merge_config($config, $localconfig) {
+        return parent::merge_config($config, $localconfig);
+    }
+
+    /**
+     * Allow access to protected method
+     * @see parent::get_config_file_contents()
+     * @param array $features
+     * @param array $stepsdefinitions
+     * @return string
+     */
+    public static function get_config_file_contents($features, $stepsdefinitions) {
+        return parent::get_config_file_contents($features, $stepsdefinitions);
+    }
+}
index e995021..ff28703 100644 (file)
@@ -941,7 +941,6 @@ class auth_plugin_mnet extends auth_plugin_base {
         // run the keepalive client
         $this->keepalive_client();
 
-        // admin/cron.php should have run srand for us
         $random100 = rand(0,100);
         if ($random100 < 10) {     // Approximately 10% of the time.
             // nuke olden sessions
index c9e5526..4f441ba 100644 (file)
@@ -309,7 +309,6 @@ class entities {
             $source = str_split($source, 1);
 
             for ($i = 1; $i <= $length; $i++) {
-                mt_srand((double) microtime() * 1000000);
                 $num = mt_rand(1, count($source));
                 $response .= $source[$num - 1];
             }
index 96526c4..4287cdd 100644 (file)
@@ -236,9 +236,20 @@ abstract class award_criteria {
      * Review this criteria and decide if the user has completed
      *
      * @param int $userid User whose criteria completion needs to be reviewed.
+     * @param bool $filtered An additional parameter indicating that user list
+     *        has been reduced and some expensive checks can be skipped.
+     *
      * @return bool Whether criteria is complete
      */
-    abstract public function review($userid);
+    abstract public function review($userid, $filtered = false);
+
+    /**
+     * Returns array with sql code and parameters returning all ids
+     * of users who meet this particular criterion.
+     *
+     * @return array list($join, $where, $params)
+     */
+    abstract public function get_completed_criteria_sql();
 
     /**
      * Mark this criteria as complete for a user
index ff9b92e..8f4d4b0 100644 (file)
@@ -37,13 +37,20 @@ class award_criteria_activity extends award_criteria {
     public $criteriatype = BADGE_CRITERIA_TYPE_ACTIVITY;
 
     private $courseid;
+    private $coursestartdate;
 
     public $required_param = 'module';
     public $optional_params = array('bydate');
 
     public function __construct($record) {
+        global $DB;
         parent::__construct($record);
-        $this->courseid = self::get_course();
+
+        $course = $DB->get_record_sql('SELECT b.courseid, c.startdate
+                        FROM {badge} b INNER JOIN {course} c ON b.courseid = c.id
+                        WHERE b.id = :badgeid ', array('badgeid' => $this->badgeid));
+        $this->courseid = $course->courseid;
+        $this->coursestartdate = $course->startdate;
     }
 
     /**
@@ -95,17 +102,6 @@ class award_criteria_activity extends award_criteria {
         }
     }
 
-    /**
-     * Return course ID for activities
-     *
-     * @return int
-     */
-    private function get_course() {
-        global $DB;
-        $courseid = $DB->get_field('badge', 'courseid', array('id' => $this->badgeid));
-        return $courseid;
-    }
-
     /**
      * Add appropriate new criteria options to the form
      *
@@ -184,14 +180,17 @@ class award_criteria_activity extends award_criteria {
      * Review this criteria and decide if it has been completed
      *
      * @param int $userid User whose criteria completion needs to be reviewed.
+     * @param bool $filtered An additional parameter indicating that user list
+     *        has been reduced and some expensive checks can be skipped.
+     *
      * @return bool Whether criteria is complete
      */
-    public function review($userid) {
-        global $DB;
+    public function review($userid, $filtered = false) {
         $completionstates = array(COMPLETION_COMPLETE, COMPLETION_COMPLETE_PASS);
-        $course = $DB->get_record('course', array('id' => $this->courseid));
+        $course = new stdClass();
+        $course->id = $this->courseid;
 
-        if ($course->startdate > time()) {
+        if ($this->coursestartdate > time()) {
             return false;
         }
 
@@ -217,7 +216,7 @@ class award_criteria_activity extends award_criteria {
                 } else {
                     return false;
                 }
-            } else if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
+            } else {
                 if (in_array($data->completionstate, $completionstates) && $check_date) {
                     return true;
                 } else {
@@ -229,4 +228,44 @@ class award_criteria_activity extends award_criteria {
 
         return $overall;
     }
+
+    /**
+     * Returns array with sql code and parameters returning all ids
+     * of users who meet this particular criterion.
+     *
+     * @return array list($join, $where, $params)
+     */
+    public function get_completed_criteria_sql() {
+        $join = '';
+        $where = '';
+        $params = array();
+
+        if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
+            foreach ($this->params as $param) {
+                $moduledata[] = " cmc.coursemoduleid = :completedmodule{$param['module']} ";
+                $params["completedmodule{$param['module']}"] = $param['module'];
+            }
+            if (!empty($moduledata)) {
+                $extraon = implode(' OR ', $moduledata);
+                $join = " JOIN {course_modules_completion} cmc ON cmc.userid = u.id AND
+                          ( cmc.completionstate = :completionpass OR cmc.completionstate = :completioncomplete ) AND ({$extraon})";
+                $params["completionpass"] = COMPLETION_COMPLETE_PASS;
+                $params["completioncomplete"] = COMPLETION_COMPLETE;
+            }
+            return array($join, $where, $params);
+        } else {
+            foreach ($this->params as $param) {
+                $join .= " LEFT JOIN {course_modules_completion} cmc{$param['module']} ON
+                          cmc{$param['module']}.userid = u.id AND
+                          cmc{$param['module']}.coursemoduleid = :completedmodule{$param['module']} AND
+                          ( cmc{$param['module']}.completionstate = :completionpass{$param['module']} OR
+                            cmc{$param['module']}.completionstate = :completioncomplete{$param['module']} )";
+                $where .= " AND cmc{$param['module']}.coursemoduleid IS NOT NULL ";
+                $params["completedmodule{$param['module']}"] = $param['module'];
+                $params["completionpass{$param['module']}"] = COMPLETION_COMPLETE_PASS;
+                $params["completioncomplete{$param['module']}"] = COMPLETION_COMPLETE;
+            }
+            return array($join, $where, $params);
+        }
+    }
 }
index c6089a2..295d927 100644 (file)
@@ -38,9 +38,23 @@ class award_criteria_course extends award_criteria {
     /* @var int Criteria [BADGE_CRITERIA_TYPE_COURSE] */
     public $criteriatype = BADGE_CRITERIA_TYPE_COURSE;
 
+    private $courseid;
+    private $coursestartdate;
+
     public $required_param = 'course';
     public $optional_params = array('grade', 'bydate');
 
+    public function __construct($record) {
+        global $DB;
+        parent::__construct($record);
+
+        $course = $DB->get_record_sql('SELECT b.courseid, c.startdate
+                        FROM {badge} b INNER JOIN {course} c ON b.courseid = c.id
+                        WHERE b.id = :badgeid ', array('badgeid' => $this->badgeid));
+        $this->courseid = $course->courseid;
+        $this->coursestartdate = $course->startdate;
+    }
+
     /**
      * Add appropriate form elements to the criteria form
      *
@@ -151,18 +165,22 @@ class award_criteria_course extends award_criteria {
      * Review this criteria and decide if it has been completed
      *
      * @param int $userid User whose criteria completion needs to be reviewed.
+     * @param bool $filtered An additional parameter indicating that user list
+     *        has been reduced and some expensive checks can be skipped.
+     *
      * @return bool Whether criteria is complete
      */
-    public function review($userid) {
-        global $DB;
-        foreach ($this->params as $param) {
-            $course = $DB->get_record('course', array('id' => $param['course']));
+    public function review($userid, $filtered = false) {
+        $course = new stdClass();
+        $course->id = $this->courseid;
 
-            if ($course->startdate > time()) {
-                return false;
-            }
+        if ($this->coursestartdate > time()) {
+            return false;
+        }
 
-            $info = new completion_info($course);
+        $info = new completion_info($course);
+
+        foreach ($this->params as $param) {
             $check_grade = true;
             $check_date = true;
 
@@ -171,7 +189,7 @@ class award_criteria_course extends award_criteria {
                 $check_grade = ($grade->grade >= $param['grade']);
             }
 
-            if (isset($param['bydate'])) {
+            if (!$filtered && isset($param['bydate'])) {
                 $cparams = array(
                         'userid' => $userid,
                         'course' => $course->id,
@@ -188,4 +206,27 @@ class award_criteria_course extends award_criteria {
 
         return false;
     }
-}
\ No newline at end of file
+
+    /**
+     * Returns array with sql code and parameters returning all ids
+     * of users who meet this particular criterion.
+     *
+     * @return array list($join, $where, $params)
+     */
+    public function get_completed_criteria_sql() {
+        // We have only one criterion here, so taking the first one.
+        $coursecriteria = reset($this->params);
+
+        $join = " LEFT JOIN {course_completions} cc ON cc.userid = u.id AND cc.timecompleted > 0";
+        $where = ' AND cc.course = :courseid ';
+        $params['courseid'] = $this->courseid;
+
+        // Add by date parameter.
+        if (isset($param['bydate'])) {
+            $where .= ' AND cc.timecompleted <= :completebydate';
+            $params['completebydate'] = $coursecriteria['bydate'];
+        }
+
+        return array($join, $where, $params);
+    }
+}
index a20e70b..5aabfe8 100644 (file)
@@ -202,12 +202,17 @@ class award_criteria_courseset extends award_criteria {
     /**
      * Review this criteria and decide if it has been completed
      *
+     * @param int $userid User whose criteria completion needs to be reviewed.
+     * @param bool $filtered An additional parameter indicating that user list
+     *        has been reduced and some expensive checks can be skipped.
+     *
      * @return bool Whether criteria is complete
      */
-    public function review($userid) {
-        global $DB;
+    public function review($userid, $filtered = false) {
         foreach ($this->params as $param) {
-            $course = $DB->get_record('course', array('id' => $param['course']));
+            $course =  new stdClass();
+            $course->id = $param['course'];
+
             $info = new completion_info($course);
             $check_grade = true;
             $check_date = true;
@@ -217,7 +222,7 @@ class award_criteria_courseset extends award_criteria {
                 $check_grade = ($grade->grade >= $param['grade']);
             }
 
-            if (isset($param['bydate'])) {
+            if (!$filtered && isset($param['bydate'])) {
                 $cparams = array(
                         'userid' => $userid,
                         'course' => $course->id,
@@ -235,7 +240,7 @@ class award_criteria_courseset extends award_criteria {
                 } else {
                     return false;
                 }
-            } else if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
+            } else {
                 if ($info->is_course_complete($userid) && $check_grade && $check_date) {
                     return true;
                 } else {
@@ -247,4 +252,39 @@ class award_criteria_courseset extends award_criteria {
 
         return $overall;
     }
+
+    /**
+     * Returns array with sql code and parameters returning all ids
+     * of users who meet this particular criterion.
+     *
+     * @return array list($join, $where, $params)
+     */
+    public function get_completed_criteria_sql() {
+        $join = '';
+        $where = '';
+        $params = array();
+
+        if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
+            foreach ($this->params as $param) {
+                $coursedata[] = " cc.course = :completedcourse{$param['course']} ";
+                $params["completedcourse{$param['course']}"] = $param['course'];
+            }
+            if (!empty($coursedata)) {
+                $extraon = implode(' OR ', $coursedata);
+                $join = " JOIN {course_completions} cc ON cc.userid = u.id AND
+                          cc.timecompleted > 0 AND ({$extraon})";
+            }
+            return array($join, $where, $params);
+        } else {
+            foreach ($this->params as $param) {
+                $join .= " LEFT JOIN {course_completions} cc{$param['course']} ON
+                          cc{$param['course']}.userid = u.id AND
+                          cc{$param['course']}.course = :completedcourse{$param['course']} AND
+                          cc{$param['course']}.timecompleted > 0 ";
+                $where .= " AND cc{$param['course']}.course IS NOT NULL ";
+                $params["completedcourse{$param['course']}"] = $param['course'];
+            }
+            return array($join, $where, $params);
+        }
+    }
 }
index 672c9f8..616ba97 100644 (file)
@@ -142,11 +142,19 @@ class award_criteria_manual extends award_criteria {
      * Review this criteria and decide if it has been completed
      *
      * @param int $userid User whose criteria completion needs to be reviewed.
+     * @param bool $filtered An additional parameter indicating that user list
+     *        has been reduced and some expensive checks can be skipped.
+     *
      * @return bool Whether criteria is complete
      */
-    public function review($userid) {
+    public function review($userid, $filtered = false) {
         global $DB;
 
+        // Users were already filtered by criteria completion.
+        if ($filtered) {
+            return true;
+        }
+
         $overall = false;
         foreach ($this->params as $param) {
             $crit = $DB->get_record('badge_manual_award', array('issuerrole' => $param['role'], 'recipientid' => $userid, 'badgeid' => $this->badgeid));
@@ -157,7 +165,7 @@ class award_criteria_manual extends award_criteria {
                     $overall = true;
                     continue;
                 }
-            } else if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
+            } else {
                 if (!$crit) {
                     $overall = false;
                     continue;
@@ -169,6 +177,41 @@ class award_criteria_manual extends award_criteria {
         return $overall;
     }
 
+    /**
+     * Returns array with sql code and parameters returning all ids
+     * of users who meet this particular criterion.
+     *
+     * @return array list($join, $where, $params)
+     */
+    public function get_completed_criteria_sql() {
+        $join = '';
+        $where = '';
+        $params = array();
+
+        if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
+            foreach ($this->params as $param) {
+                $roledata[] = " bma.issuerrole = :issuerrole{$param['role']} ";
+                $params["issuerrole{$param['role']}"] = $param['role'];
+            }
+            if (!empty($roledata)) {
+                $extraon = implode(' OR ', $roledata);
+                $join = " JOIN {badge_manual_award} bma ON bma.recipientid = u.id
+                          AND bma.badgeid = :badgeid{$this->badgeid} AND ({$extraon})";
+                $params["badgeid{$this->badgeid}"] = $this->badgeid;
+            }
+            return array($join, $where, $params);
+        } else {
+            foreach ($this->params as $param) {
+                $join .= " LEFT JOIN {badge_manual_award} bma{$param['role']} ON
+                          bma{$param['role']}.recipientid = u.id AND
+                          bma{$param['role']}.issuerrole = :issuerrole{$param['role']} ";
+                $where .= " AND bma{$param['role']}.issuerrole IS NOT NULL ";
+                $params["issuerrole{$param['role']}"] = $param['role'];
+            }
+            return array($join, $where, $params);
+        }
+    }
+
     /**
      * Delete this criterion
      *
index f04e3a4..32e8711 100644 (file)
@@ -86,9 +86,12 @@ class award_criteria_overall extends award_criteria {
      * Overall criteria review should be called only from other criteria handlers.
      *
      * @param int $userid User whose criteria completion needs to be reviewed.
+     * @param bool $filtered An additional parameter indicating that user list
+     *        has been reduced and some expensive checks can be skipped.
+     *
      * @return bool Whether criteria is complete
      */
-    public function review($userid) {
+    public function review($userid, $filtered = false) {
         global $DB;
 
         $sql = "SELECT bc.*, bcm.critid, bcm.userid, bcm.datemet
@@ -114,7 +117,7 @@ class award_criteria_overall extends award_criteria {
                     $overall = true;
                     continue;
                 }
-            } else if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
+            } else {
                 if ($crit->datemet === null) {
                     $overall = false;
                     continue;
@@ -127,6 +130,16 @@ class award_criteria_overall extends award_criteria {
         return $overall;
     }
 
+    /**
+     * Returns array with sql code and parameters returning all ids
+     * of users who meet this particular criterion.
+     *
+     * @return array list($join, $where, $params)
+     */
+    public function get_completed_criteria_sql() {
+        return array('', '', array());
+    }
+
     /**
      * Add appropriate criteria elements to the form
      *
index 9940e90..18915a0 100644 (file)
@@ -156,35 +156,86 @@ class award_criteria_profile extends award_criteria {
      * Review this criteria and decide if it has been completed
      *
      * @param int $userid User whose criteria completion needs to be reviewed.
+     * @param bool $filtered An additional parameter indicating that user list
+     *        has been reduced and some expensive checks can be skipped.
+     *
      * @return bool Whether criteria is complete
      */
-    public function review($userid) {
+    public function review($userid, $filtered = false) {
         global $DB;
 
-        $overall = false;
+        // Users were already filtered by criteria completion, no checks required.
+        if ($filtered) {
+            return true;
+        }
+
+        $join = '';
+        $where = '';
+        $sqlparams = array();
+        $rule = ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) ? ' OR ' : ' AND ';
+
         foreach ($this->params as $param) {
             if (is_numeric($param['field'])) {
-                $crit = $DB->get_field('user_info_data', 'data', array('userid' => $userid, 'fieldid' => $param['field']));
+                $infodata[] = " uid.fieldid = :fieldid{$param['field']} ";
+                $sqlparams["fieldid{$param['field']}"] = $param['field'];
             } else {
-                $crit = $DB->get_field('user', $param['field'], array('id' => $userid));
+                $userdata[] = $DB->sql_isnotempty('u', "u.{$param['field']}", false, true);
             }
+        }
 
-            if ($this->method == BADGE_CRITERIA_AGGREGATION_ALL) {
-                if (!$crit) {
-                    return false;
-                } else {
-                    $overall = true;
-                    continue;
-                }
-            } else if ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) {
-                if (!$crit) {
-                    $overall = false;
-                    continue;
-                } else {
-                    return true;
-                }
-            }
+        // Add user custom field parameters if there are any.
+        if (!empty($infodata)) {
+            $extraon = implode($rule, $infodata);
+            $join = " LEFT JOIN {user_info_data} uid ON uid.userid = u.id AND ({$extraon})";
         }
+
+        // Add user table field parameters if there are any.
+        if (!empty($userdata)) {
+            $extraon = implode($rule, $userdata);
+            $where = " AND ({$extraon})";
+        }
+
+        $sqlparams['userid'] = $userid;
+        $sql = "SELECT u.* FROM {user} u " . $join . " WHERE u.id = :userid " . $where;
+        $overall = $DB->record_exists_sql($sql, $sqlparams);
+
         return $overall;
     }
+
+    /**
+     * Returns array with sql code and parameters returning all ids
+     * of users who meet this particular criterion.
+     *
+     * @return array list($join, $where, $params)
+     */
+    public function get_completed_criteria_sql() {
+        global $DB;
+
+        $join = '';
+        $where = '';
+        $params = array();
+        $rule = ($this->method == BADGE_CRITERIA_AGGREGATION_ANY) ? ' OR ' : ' AND ';
+
+        foreach ($this->params as $param) {
+            if (is_numeric($param['field'])) {
+                $infodata[] = " uid.fieldid = :fieldid{$param['field']} ";
+                $params["fieldid{$param['field']}"] = $param['field'];
+            } else {
+                $userdata[] = $DB->sql_isnotempty('u', "u.{$param['field']}", false, true);
+            }
+        }
+
+        // Add user custom fields if there are any.
+        if (!empty($infodata)) {
+            $extraon = implode($rule, $infodata);
+            $join = " LEFT JOIN {user_info_data} uid ON uid.userid = u.id AND ({$extraon})";
+        }
+
+        // Add user table fields if there are any.
+        if (!empty($userdata)) {
+            $extraon = implode($rule, $userdata);
+            $where = " AND ({$extraon})";
+        }
+        return array($join, $where, $params);
+    }
 }
index b70d377..97b3271 100644 (file)
@@ -292,9 +292,10 @@ class core_badges_badgeslib_testcase extends advanced_testcase {
         $criteria_overall = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_OVERALL, 'badgeid' => $badge->id));
         $criteria_overall->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ANY));
         $criteria_overall1 = award_criteria::build(array('criteriatype' => BADGE_CRITERIA_TYPE_PROFILE, 'badgeid' => $badge->id));
-        $criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL, 'field_address' => 'address'));
+        $criteria_overall1->save(array('agg' => BADGE_CRITERIA_AGGREGATION_ALL, 'field_address' => 'address', 'field_aim' => 'aim'));
 
         $this->user->address = 'Test address';
+        $this->user->aim = '999999999';
         $sink = $this->redirectEmails();
         user_update_user($this->user, false);
         $this->assertCount(1, $sink->get_messages());
diff --git a/badges/upgrade.txt b/badges/upgrade.txt
new file mode 100644 (file)
index 0000000..1a48ffd
--- /dev/null
@@ -0,0 +1,12 @@
+This files describes API changes in /badges/*,
+information provided here is intended especially for developers.
+
+=== 2.7 ===
+
+* get_completed_criteria_sql() - This method was added to award_criteria class and must be overriden
+  in all criteria classes. This method returns an array consisting of SQL JOIN statement, WHERE conditions,
+  and any parameters that might be required. The results are used in lib/badgeslib.php in review_all_criteria()
+  to reduce to the minimum the number of users to review and award badges.
+
+* New optional parameter $filtered in review() allows to indicate that some expensive checks can be skipped
+  if the list of users has been initially filtered based on met criteria.
index a591ad9..e720c18 100644 (file)
@@ -23,7 +23,7 @@ YUI.add('moodle-block_community-comments', function(Y) {
                         .append(Y.one('#commentoverlay-'+commentid+' .commenttitle').get('innerHTML')),
                     bodyContent:Y.one('#commentoverlay-'+commentid).get('innerHTML'),
                     visible: false, //by default it is not displayed
-                    lightbox : false,
+                    modal: false,
                     zIndex:100,
                     closeButtonTitle: this.get('closeButtonTitle')
                 });
index 7696f20..b48a204 100644 (file)
@@ -38,7 +38,7 @@ YUI.add('moodle-block_community-imagegallery', function(Y) {
                 headerContent:Y.one('#imagetitleoverlay').get('innerHTML'),
                 bodyContent:Y.one('#imageoverlay').get('innerHTML'),
                 visible: false, //by default it is not displayed
-                lightbox : false,
+                modal: false,
                 zIndex:100
             });
 
@@ -101,7 +101,7 @@ YUI.add('moodle-block_community-imagegallery', function(Y) {
                 + screennumber + ' / ' + this.imageidnumbers[imageid] + ' </h1></div>' + nextimagelink,
                 bodyContent:Y.one('#imageoverlay').get('innerHTML'),
                 visible: false, //by default it is not displayed
-                lightbox : false,
+                modal: false,
                 zIndex:100,
                 closeButtonTitle: this.get('closeButtonTitle')
             });
index d459982..d4b9f94 100644 (file)
@@ -128,8 +128,7 @@ class block_course_list extends block_list {
             $this->content->items[] = get_string('remotecourses','mnet');
             $this->content->icons[] = '';
             foreach ($courses as $course) {
-                $coursecontext = context_course::instance($course->id);
-                $this->content->items[]="<a title=\"" . format_string($course->shortname, true, array('context' => $coursecontext)) . "\" ".
+                $this->content->items[]="<a title=\"" . format_string($course->shortname, true) . "\" ".
                     "href=\"{$CFG->wwwroot}/auth/mnet/jump.php?hostid={$course->hostid}&amp;wantsurl=/course/view.php?id={$course->remoteid}\">"
                     .$icon. format_string(get_course_display_name_for_list($course)) . "</a>";
             }
index 7a116ee..cb86259 100644 (file)
Binary files a/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-debug.js and b/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-debug.js differ
index c48a7c3..e3f475d 100644 (file)
Binary files a/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-min.js and b/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation-min.js differ
index 0ecd3b9..7e484e0 100644 (file)
Binary files a/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation.js and b/blocks/navigation/yui/build/moodle-block_navigation-navigation/moodle-block_navigation-navigation.js differ
index 7db6ca9..1ff285d 100644 (file)
@@ -648,7 +648,7 @@ BRANCH.prototype = {
         try {
             var object = Y.JSON.parse(outcome.responseText);
             if (object.error) {
-                Y.use('moodle-core-notification-ajaxException', function () {
+                Y.use('moodle-core-notification-ajaxexception', function () {
                     return new M.core.ajaxException(object).show();
                 });
                 return false;
index 4463e0a..e6e341a 100644 (file)
@@ -281,7 +281,7 @@ class cache_definition {
      * An array of identifiers provided to this cache when it was initialised.
      * @var array
      */
-    protected $identifiers = array();
+    protected $identifiers = null;
 
     /**
      * Key prefix for use with single key cache stores
@@ -654,6 +654,9 @@ class cache_definition {
      * @return array
      */
     public function get_identifiers() {
+        if (!isset($this->identifiers)) {
+            return array();
+        }
         return $this->identifiers;
     }
 
@@ -766,11 +769,22 @@ class cache_definition {
      * @throws coding_exception
      */
     public function set_identifiers(array $identifiers = array()) {
+        // If we are setting the exact same identifiers then just return as nothing really changed.
+        // We don't care about order as cache::make will use the same definition order all the time.
+        if ($identifiers === $this->identifiers) {
+            return;
+        }
+
         foreach ($this->requireidentifiers as $identifier) {
             if (!isset($identifiers[$identifier])) {
                 throw new coding_exception('Identifier required for cache has not been provided: '.$identifier);
             }
         }
+
+        if ($this->identifiers === null) {
+            // Initialize identifiers if they have not been.
+            $this->identifiers = array();
+        }
         foreach ($identifiers as $name => $value) {
             $this->identifiers[$name] = (string)$value;
         }
@@ -893,7 +907,7 @@ class cache_definition {
                 'area' => $this->area,
                 'siteidentifier' => $this->get_cache_identifier()
             );
-            if (!empty($this->identifiers)) {
+            if (isset($this->identifiers) && !empty($this->identifiers)) {
                 $identifiers = array();
                 foreach ($this->identifiers as $key => $value) {
                     $identifiers[] = htmlentities($key, ENT_QUOTES, 'UTF-8').'='.htmlentities($value, ENT_QUOTES, 'UTF-8');
index c71f108..1ee6e5e 100644 (file)
@@ -131,7 +131,7 @@ class cachestore_memcache extends cache_store implements cache_is_configurable {
 
         $this->connection = new Memcache;
         foreach ($this->servers as $server) {
-            $this->connection->addServer($server[0], $server[1], true, $server[2]);
+            $this->connection->addServer($server[0], (int) $server[1], true, (int) $server[2]);
         }
         // Test the connection to the pool of servers.
         $this->isready = @$this->connection->set($this->parse_key('ping'), 'ping', MEMCACHE_COMPRESSED, 1);
index e7f1631..451fa87 100644 (file)
@@ -584,22 +584,12 @@ $CFG->admin = 'admin';
 //=========================================================================
 // 11. BEHAT SUPPORT
 //=========================================================================
-// Behat needs a separate data directory and unique database prefix:
+// Behat test site needs a unique www root, data directory and database prefix:
 //
+// $CFG->behat_wwwroot = 'http://127.0.0.1/moodle';
 // $CFG->behat_prefix = 'bht_';
 // $CFG->behat_dataroot = '/home/example/bht_moodledata';
 //
-// To set a seperate wwwroot for Behat to use, use $CFG->behat_wwwroot; this is set automatically
-// to http://localhost:8000 as it is the proposed PHP built-in server URL. Instead of that you can,
-// for example, use an alias, add a host to /etc/hosts or add a new virtual host having a URL
-// poiting to your production site and another one poiting to your test site. Note that you need
-// to ensure that this URL is not accessible from the www as the behat test site uses "sugar"
-// credentials (admin/admin) and can be easily hackable.
-//
-// Example:
-//   $CFG->behat_wwwroot = 'http://192.168.1.250:8000';
-//   $CFG->behat_wwwroot = 'http://localhost/moodlesitetesting';
-//
 // You can override default Moodle configuration for Behat and add your own
 // params; here you can add more profiles, use different Mink drivers than Selenium...
 // These params would be merged with the default Moodle behat.yml, giving priority
@@ -644,16 +634,6 @@ $CFG->admin = 'admin';
 //       )
 //   );
 //
-// You can completely switch to test environment when "php admin/tool/behat/cli/util --enable",
-// this means that all the site accesses will be routed to the test environment instead of
-// the regular one, so NEVER USE THIS SETTING IN PRODUCTION SITES. This setting is useful
-// when working with cloud CI (continous integration) servers which requires public sites to run the
-// tests, or in testing/development installations when you are developing in a pre-PHP 5.4 server.
-// Note that with this setting enabled $CFG->behat_wwwroot is ignored and $CFG->behat_wwwroot
-// value will be the regular $CFG->wwwroot value.
-// Example:
-//   $CFG->behat_switchcompletely = true;
-//
 // You can force the browser session (not user's sessions) to restart after N seconds. This could
 // be useful if you are using a cloud-based service with time restrictions in the browser side.
 // Setting this value the browser session that Behat is using will be restarted. Set the time in
index d279d39..00b19d4 100644 (file)
@@ -736,38 +736,13 @@ M.course_dndupload = {
                     var result = JSON.parse(xhr.responseText);
                     if (result) {
                         if (result.error == 0) {
-                            // All OK - update the dummy element
-                            if (result.content) {
-                                // A label
-                                resel.indentdiv.innerHTML = '<div class="activityinstance" ></div>' + result.content + result.commands;
-                            } else {
-                                // Not a label
-                                resel.icon.src = result.icon;
-                                resel.a.href = result.link;
-                                resel.namespan.innerHTML = result.name;
-
-                                if (!parseInt(result.visible, 10)) {
-                                    resel.a.className = 'dimmed';
-                                }
-
-                                if (result.groupingname) {
-                                    resel.groupingspan.innerHTML = '(' + result.groupingname + ')';
-                                } else {
-                                    resel.div.removeChild(resel.groupingspan);
-                                }
-
-                                resel.div.removeChild(resel.progressouter);
-                                resel.indentdiv.innerHTML += result.commands;
-                                if (result.onclick) {
-                                    resel.a.onclick = result.onclick;
-                                }
-                                if (self.Y.UA.gecko > 0) {
-                                    // Fix a Firefox bug which makes sites with a '~' in their wwwroot
-                                    // log the user out when clicking on the link (before refreshing the page).
-                                    resel.div.innerHTML = unescape(resel.div.innerHTML);
-                                }
+                            // All OK - replace the dummy element.
+                            resel.li.outerHTML = result.fullcontent;
+                            if (self.Y.UA.gecko > 0) {
+                                // Fix a Firefox bug which makes sites with a '~' in their wwwroot
+                                // log the user out when clicking on the link (before refreshing the page).
+                                resel.li.outerHTML = unescape(resel.li.outerHTML);
                             }
-                            resel.li.id = result.elementid;
                             self.add_editing(result.elementid);
                         } else {
                             // Error - remove the dummy element
@@ -986,39 +961,14 @@ M.course_dndupload = {
                     var result = JSON.parse(xhr.responseText);
                     if (result) {
                         if (result.error == 0) {
-                            // All OK - update the dummy element
-                            if (result.content) {
-                                // A label
-                                resel.indentdiv.innerHTML = '<div class="activityinstance" ></div>' + result.content + result.commands;
-                            } else {
-                                // Not a label
-                                resel.icon.src = result.icon;
-                                resel.a.href = result.link;
-                                resel.namespan.innerHTML = result.name;
-
-                                if (!parseInt(result.visible, 10)) {
-                                    resel.a.className = 'dimmed';
-                                }
-
-                                if (result.groupingname) {
-                                    resel.groupingspan.innerHTML = '(' + result.groupingname + ')';
-                                } else {
-                                    resel.div.removeChild(resel.groupingspan);
-                                }
-
-                                resel.div.removeChild(resel.progressouter);
-                                resel.div.innerHTML += result.commands;
-                                if (result.onclick) {
-                                    resel.a.onclick = result.onclick;
-                                }
-                                if (self.Y.UA.gecko > 0) {
-                                    // Fix a Firefox bug which makes sites with a '~' in their wwwroot
-                                    // log the user out when clicking on the link (before refreshing the page).
-                                    resel.div.innerHTML = unescape(resel.div.innerHTML);
-                                }
+                            // All OK - replace the dummy element.
+                            resel.li.outerHTML = result.fullcontent;
+                            if (self.Y.UA.gecko > 0) {
+                                // Fix a Firefox bug which makes sites with a '~' in their wwwroot
+                                // log the user out when clicking on the link (before refreshing the page).
+                                resel.li.outerHTML = unescape(resel.li.outerHTML);
                             }
-                            resel.li.id = result.elementid;
-                            self.add_editing(result.elementid, sectionnumber);
+                            self.add_editing(result.elementid);
                         } else {
                             // Error - remove the dummy element
                             resel.parent.removeChild(resel.li);
index 3fa6bb2..84aea52 100644 (file)
@@ -722,29 +722,18 @@ class dndupload_ajax_processor {
      */
     protected function send_response($mod) {
         global $OUTPUT, $PAGE;
-        $courserenderer = $PAGE->get_renderer('core', 'course');
 
         $resp = new stdClass();
         $resp->error = self::ERROR_OK;
-        $resp->icon = $mod->get_icon_url()->out();
-        $resp->name = $mod->name;
-        if ($mod->has_view()) {
-            $resp->link = $mod->get_url()->out();
-        } else {
-            $resp->link = null;
-        }
-        $resp->content = $mod->get_content();
-        $resp->elementid = 'module-'.$mod->id;
-        $actions = course_get_cm_edit_actions($mod, 0, $mod->sectionnum);
-        $resp->commands = ' '. $courserenderer->course_section_cm_edit_actions($actions, $mod);
-        $resp->onclick = $mod->get_on_click();
-        $resp->visible = $mod->visible;
-
-        // If using groupings, then display grouping name.
-        if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', $this->context)) {
-            $groupings = groups_get_all_groupings($this->course->id);
-            $resp->groupingname = format_string($groupings[$mod->groupingid]->name);
-        }
+        $resp->elementid = 'module-' . $mod->id;
+
+        $courserenderer = $PAGE->get_renderer('core', 'course');
+        $completioninfo = new completion_info($this->course);
+        $info = get_fast_modinfo($this->course);
+        $sr = null;
+        $modulehtml = $courserenderer->course_section_cm($this->course, $completioninfo,
+                $mod, null, array());
+        $resp->fullcontent = $courserenderer->course_section_cm_list_item($this->course, $completioninfo, $mod, $sr);
 
         echo $OUTPUT->header();
         echo json_encode($resp);
index 2f3ef23..d4e49b9 100644 (file)
@@ -43,15 +43,12 @@ define('COURSE_MAX_COURSES_PER_DROPDOWN', 1000);
 // Max users in log dropdown before switching to optional.
 define('COURSE_MAX_USERS_PER_DROPDOWN', 1000);
 define('FRONTPAGENEWS', '0');
-define('FRONTPAGECOURSELIST', '1'); // Not used. TODO MDL-38832 remove.
 define('FRONTPAGECATEGORYNAMES', '2');
-define('FRONTPAGETOPICONLY', '3'); // Not used. TODO MDL-38832 remove.
 define('FRONTPAGECATEGORYCOMBO', '4');
 define('FRONTPAGEENROLLEDCOURSELIST', '5');
 define('FRONTPAGEALLCOURSELIST', '6');
 define('FRONTPAGECOURSESEARCH', '7');
 // Important! Replaced with $CFG->frontpagecourselimit - maximum number of courses displayed on the frontpage.
-define('FRONTPAGECOURSELIMIT',    200); // TODO MDL-38832 remove.
 define('EXCELROWS', 65535);
 define('FIRSTUSEDEXCELROW', 3);
 
diff --git a/course/tests/behat/activities_edit_with_block_dock.feature b/course/tests/behat/activities_edit_with_block_dock.feature
new file mode 100644 (file)
index 0000000..89d1717
--- /dev/null
@@ -0,0 +1,29 @@
+@core @core_course
+Feature: Open the edit menu when a block is docked
+  In order to edit an activity with a block docked
+  As a teacher
+  I need to open the action menu
+
+  @javascript
+  Scenario: Open the action menu with a block docked
+    Given the following "users" exists:
+      | username | firstname | lastname | email |
+      | teacher1 | Teacher | 1 | teacher1@asd.com |
+    And the following "courses" exists:
+      | fullname | shortname | format |
+      | Course 1 | C1 | weeks |
+    And the following "course enrolments" exists:
+      | user | course | role |
+      | teacher1 | C1 | editingteacher |
+    And I log in as "teacher1"
+    And I follow "Course 1"
+    And I turn editing mode on
+    And I add a "Glossary" to section "1" and I fill the form with:
+      | Name | Test glossary name |
+      | Description | Test glossary description |
+    And I dock "Navigation" block
+    When I open "Test glossary name" actions menu
+    Then "Test glossary name" actions menu should be open
+    And I reload the page
+    When I open "Test glossary name" actions menu
+    Then "Test glossary name" actions menu should be open
index d31c1b9..07b948f 100644 (file)
@@ -643,6 +643,29 @@ class behat_course extends behat_base {
         return new Given('I click on "a[role=\'menuitem\']" "css_element" in the "' . $this->escape($activityname) . '" activity');
     }
 
+    /**
+     * Checks that the specified activity's action menu is open.
+     *
+     * @Then /^"(?P<activity_name_string>(?:[^"]|\\")*)" actions menu should be open$/
+     * @throws DriverException The step is not available when Javascript is disabled
+     * @param string $activityname
+     */
+    public function actions_menu_should_be_open($activityname) {
+
+        if (!$this->running_javascript()) {
+            throw new DriverException('Activities actions menu not available when Javascript is disabled');
+        }
+
+        // If it is already closed we do nothing.
+        $activitynode = $this->get_activity_node($activityname);
+        $classes = array_flip(explode(' ', $activitynode->getAttribute('class')));
+        if (empty($classes['action-menu-shown'])) {
+            throw new ExpectationException(sprintf("The action menu for '%s' is not open", $activityname), $this->getSession());
+        }
+
+        return;
+    }
+
     /**
      * Indents to the right the activity or resource specified by it's name. Editing mode should be on.
      *
index 5430b6c..16b2ca0 100644 (file)
         $PAGE->set_button($buttons);
     }
 
-    $PAGE->set_title(get_string('course') . ': ' . $course->fullname);
+    // If viewing a section, make the title more specific
+    if ($section and $section > 0 and course_format_uses_sections($course->format)) {
+        $sectionname = get_string('sectionname', "format_$course->format");
+        $sectiontitle = get_section_name($course, $section);
+        $PAGE->set_title(get_string('coursesectiontitle', 'moodle', array('course' => $course->fullname, 'sectiontitle' => $sectiontitle, 'sectionname' => $sectionname)));
+    } else {
+        $PAGE->set_title(get_string('coursetitle', 'moodle', array('course' => $course->fullname)));
+    }
+
     $PAGE->set_heading($course->fullname);
     echo $OUTPUT->header();
 
diff --git a/course/yui/build/moodle-course-modchooser/moodle-course-modchooser-debug.js b/course/yui/build/moodle-course-modchooser/moodle-course-modchooser-debug.js
new file mode 100644 (file)
index 0000000..96126f3
Binary files /dev/null and b/course/yui/build/moodle-course-modchooser/moodle-course-modchooser-debug.js differ
diff --git a/course/yui/build/moodle-course-modchooser/moodle-course-modchooser-min.js b/course/yui/build/moodle-course-modchooser/moodle-course-modchooser-min.js
new file mode 100644 (file)
index 0000000..33f576f
Binary files /dev/null and b/course/yui/build/moodle-course-modchooser/moodle-course-modchooser-min.js differ
diff --git a/course/yui/build/moodle-course-modchooser/moodle-course-modchooser.js b/course/yui/build/moodle-course-modchooser/moodle-course-modchooser.js
new file mode 100644 (file)
index 0000000..96126f3
Binary files /dev/null and b/course/yui/build/moodle-course-modchooser/moodle-course-modchooser.js differ
diff --git a/course/yui/modchooser/modchooser.js b/course/yui/modchooser/modchooser.js
deleted file mode 100644 (file)
index ce39f93..0000000
+++ /dev/null
@@ -1,166 +0,0 @@
-YUI.add('moodle-course-modchooser', function(Y) {
-    var CSS = {
-        PAGECONTENT : 'div#page-content',
-        SECTION : 'li.section',
-        SECTIONMODCHOOSER : 'span.section-modchooser-link',
-        SITEMENU : 'div.block_site_main_menu',
-        SITETOPIC : 'div.sitetopic'
-    };
-
-    var MODCHOOSERNAME = 'course-modchooser';
-
-    var MODCHOOSER = function() {
-        MODCHOOSER.superclass.constructor.apply(this, arguments);
-    }
-
-    Y.extend(MODCHOOSER, M.core.chooserdialogue, {
-        // The current section ID
-        sectionid : null,
-
-        // The hidden element holding the jump param
-        jumplink : null,
-
-        initializer : function(config) {
-            var dialogue = Y.one('.chooserdialoguebody');
-            var header = Y.one('.choosertitle');
-            var params = {};
-            this.setup_chooser_dialogue(dialogue, header, params);
-
-            // Initialize existing sections and register for dynamically created sections
-            this.setup_for_section();
-            M.course.coursebase.register_module(this);
-
-            // Catch the page toggle
-            Y.all('.block_settings #settingsnav .type_course .modchoosertoggle a').on('click', this.toggle_mod_chooser, this);
-        },
-        /**
-         * Update any section areas within the scope of the specified
-         * selector with AJAX equivalents
-         *
-         * @param baseselector The selector to limit scope to
-         * @return void
-         */
-        setup_for_section : function(baseselector) {
-            if (!baseselector) {
-                var baseselector = CSS.PAGECONTENT;
-            }
-
-            // Setup for site topics
-            Y.one(baseselector).all(CSS.SITETOPIC).each(function(section) {
-                this._setup_for_section(section);
-            }, this);
-
-            // Setup for standard course topics
-            Y.one(baseselector).all(CSS.SECTION).each(function(section) {
-                this._setup_for_section(section);
-            }, this);
-
-            // Setup for the block site menu
-            Y.one(baseselector).all(CSS.SITEMENU).each(function(section) {
-                this._setup_for_section(section);
-            }, this);
-        },
-        _setup_for_section : function(section, sectionid) {
-            var chooserspan = section.one(CSS.SECTIONMODCHOOSER);
-            if (!chooserspan) {
-                return;
-            }
-            var chooserlink = Y.Node.create("<a href='#' />");
-            chooserspan.get('children').each(function(node) {
-                chooserlink.appendChild(node);
-            });
-            chooserspan.insertBefore(chooserlink);
-            chooserlink.on('click', this.display_mod_chooser, this);
-        },
-        /**
-         * Display the module chooser
-         *
-         * @param e Event Triggering Event
-         * @param secitonid integer The ID of the section triggering the dialogue
-         * @return void
-         */
-        display_mod_chooser : function (e) {
-            // Set the section for this version of the dialogue
-            if (e.target.ancestor(CSS.SITETOPIC)) {
-                // The site topic has a sectionid of 1
-                this.sectionid = 1;
-            } else if (e.target.ancestor(CSS.SECTION)) {
-                var section = e.target.ancestor(CSS.SECTION);
-                this.sectionid = section.get('id').replace('section-', '');
-            } else if (e.target.ancestor(CSS.SITEMENU)) {
-                // The block site menu has a sectionid of 0
-                this.sectionid = 0;
-            }
-            this.display_chooser(e);
-        },
-        toggle_mod_chooser : function(e) {
-            // Get the add section link
-            var modchooserlinks = Y.all('div.addresourcemodchooser');
-
-            // Get the dropdowns
-            var dropdowns = Y.all('div.addresourcedropdown');
-
-            if (modchooserlinks.size() == 0) {
-                // Continue with non-js action if there are no modchoosers to add
-                return;
-            }
-
-            // We need to update the text and link
-            var togglelink = Y.one('.block_settings #settingsnav .type_course .modchoosertoggle a');
-
-            // The actual text is in the last child
-            var toggletext = togglelink.get('lastChild');
-
-            var usemodchooser;
-            // Determine whether they're currently hidden
-            if (modchooserlinks.item(0).hasClass('visibleifjs')) {
-                // The modchooser is currently visible, hide it
-                usemodchooser = 0;
-                modchooserlinks
-                    .removeClass('visibleifjs')
-                    .addClass('hiddenifjs');
-                dropdowns
-                    .addClass('visibleifjs')
-                    .removeClass('hiddenifjs');
-                toggletext.set('data', M.util.get_string('modchooserenable', 'moodle'));
-                togglelink.set('href', togglelink.get('href').replace('off', 'on'));
-            } else {
-                // The modchooser is currently not visible, show it
-                usemodchooser = 1;
-                modchooserlinks
-                    .addClass('visibleifjs')
-                    .removeClass('hiddenifjs');
-                dropdowns
-                    .removeClass('visibleifjs')
-                    .addClass('hiddenifjs');
-                toggletext.set('data', M.util.get_string('modchooserdisable', 'moodle'));
-                togglelink.set('href', togglelink.get('href').replace('on', 'off'));
-            }
-
-            M.util.set_user_preference('usemodchooser', usemodchooser);
-
-            // Prevent the page from reloading
-            e.preventDefault();
-        },
-        option_selected : function(thisoption) {
-            // Add the sectionid to the URL
-            this.jumplink.set('value', thisoption.get('value') + '&section=' + this.sectionid);
-        }
-    },
-    {
-        NAME : MODCHOOSERNAME,
-        ATTRS : {
-            maxheight : {
-                value : 800
-            }
-        }
-    });
-    M.course = M.course || {};
-    M.course.init_chooser = function(config) {
-        return new MODCHOOSER(config);
-    }
-},
-'@VERSION@', {
-    requires:['base', 'overlay', 'moodle-core-chooserdialogue', 'moodle-course-coursebase']
-}
-);
diff --git a/course/yui/src/modchooser/build.json b/course/yui/src/modchooser/build.json
new file mode 100644 (file)
index 0000000..569ab7b
--- /dev/null
@@ -0,0 +1,10 @@
+{
+  "name": "moodle-course-modchooser",
+  "builds": {
+    "moodle-course-modchooser": {
+      "jsfiles": [
+        "modchooser.js"
+      ]
+    }
+  }
+}
diff --git a/course/yui/src/modchooser/js/modchooser.js b/course/yui/src/modchooser/js/modchooser.js
new file mode 100644 (file)
index 0000000..0bd9825
--- /dev/null
@@ -0,0 +1,173 @@
+/**
+ * The activity chooser dialogue for courses.
+ *
+ * @moodle-course-modchooser
+ */
+
+var CSS = {
+    PAGECONTENT : 'div#page-content',
+    SECTION : 'li.section',
+    SECTIONMODCHOOSER : 'span.section-modchooser-link',
+    SITEMENU : 'div.block_site_main_menu',
+    SITETOPIC : 'div.sitetopic'
+};
+
+var MODCHOOSERNAME = 'course-modchooser';
+
+/**
+ * The activity chooser dialogue for courses.
+ *
+ * @constructor
+ * @class M.course.modchooser
+ * @extends M.core.chooserdialogue
+ */
+var MODCHOOSER = function() {
+    MODCHOOSER.superclass.constructor.apply(this, arguments);
+};
+
+Y.extend(MODCHOOSER, M.core.chooserdialogue, {
+    // The current section ID
+    sectionid : null,
+
+    // The hidden element holding the jump param
+    jumplink : null,
+
+    initializer : function() {
+        var dialogue = Y.one('.chooserdialoguebody');
+        var header = Y.one('.choosertitle');
+        var params = {};
+        this.setup_chooser_dialogue(dialogue, header, params);
+
+        // Initialize existing sections and register for dynamically created sections
+        this.setup_for_section();
+        M.course.coursebase.register_module(this);
+
+        // Catch the page toggle
+        Y.all('.block_settings #settingsnav .type_course .modchoosertoggle a').on('click', this.toggle_mod_chooser, this);
+    },
+    /**
+     * Update any section areas within the scope of the specified
+     * selector with AJAX equivalents
+     *
+     * @param baseselector The selector to limit scope to
+     * @return void
+     */
+    setup_for_section : function(baseselector) {
+        if (!baseselector) {
+            baseselector = CSS.PAGECONTENT;
+        }
+
+        // Setup for site topics
+        Y.one(baseselector).all(CSS.SITETOPIC).each(function(section) {
+            this._setup_for_section(section);
+        }, this);
+
+        // Setup for standard course topics
+        Y.one(baseselector).all(CSS.SECTION).each(function(section) {
+            this._setup_for_section(section);
+        }, this);
+
+        // Setup for the block site menu
+        Y.one(baseselector).all(CSS.SITEMENU).each(function(section) {
+            this._setup_for_section(section);
+        }, this);
+    },
+    _setup_for_section : function(section) {
+        var chooserspan = section.one(CSS.SECTIONMODCHOOSER);
+        if (!chooserspan) {
+            return;
+        }
+        var chooserlink = Y.Node.create("<a href='#' />");
+        chooserspan.get('children').each(function(node) {
+            chooserlink.appendChild(node);
+        });
+        chooserspan.insertBefore(chooserlink);
+        chooserlink.on('click', this.display_mod_chooser, this);
+    },
+    /**
+        * Display the module chooser
+        *
+        * @param e Event Triggering Event
+        * @param secitonid integer The ID of the section triggering the dialogue
+        * @return void
+        */
+    display_mod_chooser : function (e) {
+        // Set the section for this version of the dialogue
+        if (e.target.ancestor(CSS.SITETOPIC)) {
+            // The site topic has a sectionid of 1
+            this.sectionid = 1;
+        } else if (e.target.ancestor(CSS.SECTION)) {
+            var section = e.target.ancestor(CSS.SECTION);
+            this.sectionid = section.get('id').replace('section-', '');
+        } else if (e.target.ancestor(CSS.SITEMENU)) {
+            // The block site menu has a sectionid of 0
+            this.sectionid = 0;
+        }
+        this.display_chooser(e);
+    },
+    toggle_mod_chooser : function(e) {
+        // Get the add section link
+        var modchooserlinks = Y.all('div.addresourcemodchooser');
+
+        // Get the dropdowns
+        var dropdowns = Y.all('div.addresourcedropdown');
+
+        if (modchooserlinks.size() === 0) {
+            // Continue with non-js action if there are no modchoosers to add
+            return;
+        }
+
+        // We need to update the text and link
+        var togglelink = Y.one('.block_settings #settingsnav .type_course .modchoosertoggle a');
+
+        // The actual text is in the last child
+        var toggletext = togglelink.get('lastChild');
+
+        var usemodchooser;
+        // Determine whether they're currently hidden
+        if (modchooserlinks.item(0).hasClass('visibleifjs')) {
+            // The modchooser is currently visible, hide it
+            usemodchooser = 0;
+            modchooserlinks
+                .removeClass('visibleifjs')
+                .addClass('hiddenifjs');
+            dropdowns
+                .addClass('visibleifjs')
+                .removeClass('hiddenifjs');
+            toggletext.set('data', M.util.get_string('modchooserenable', 'moodle'));
+            togglelink.set('href', togglelink.get('href').replace('off', 'on'));
+        } else {
+            // The modchooser is currently not visible, show it
+            usemodchooser = 1;
+            modchooserlinks
+                .addClass('visibleifjs')
+                .removeClass('hiddenifjs');
+            dropdowns
+                .removeClass('visibleifjs')
+                .addClass('hiddenifjs');
+            toggletext.set('data', M.util.get_string('modchooserdisable', 'moodle'));
+            togglelink.set('href', togglelink.get('href').replace('on', 'off'));
+        }
+
+        M.util.set_user_preference('usemodchooser', usemodchooser);
+
+        // Prevent the page from reloading
+        e.preventDefault();
+    },
+    option_selected : function(thisoption) {
+        // Add the sectionid to the URL
+        this.jumplink.set('value', thisoption.get('value') + '&section=' + this.sectionid);
+    }
+},
+{
+    NAME : MODCHOOSERNAME,
+    ATTRS : {
+        maxheight : {
+            value : 800
+        }
+    }
+});
+M.course = M.course || {};
+M.course.init_chooser = function(config) {
+    return new MODCHOOSER(config);
+};
diff --git a/course/yui/src/modchooser/meta/modchooser.json b/course/yui/src/modchooser/meta/modchooser.json
new file mode 100644 (file)
index 0000000..2ef461b
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  "moodle-course-modchooser": {
+    "requires": [
+        "moodle-core-chooserdialogue",
+        "moodle-course-coursebase"
+    ]
+  }
+}
index 8362185..dee47d8 100644 (file)
@@ -156,11 +156,8 @@ YUI.add('moodle-enrol_manual-quickenrolment', function(Y) {
             }
 
             this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).one('img').setAttribute('src', M.util.image_url(collapsedimage, 'moodle'));
-            this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).once('click', function() {
-                // We want to do this just once, the first time the controls are shown.
-                this.populateStartDates();
-                this.populateDuration();
-            }, this);
+            this.populateStartDates();
+            this.populateDuration();
             this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).on('click', function(){
                 this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEHEADING).toggleClass(CSS.ACTIVE);
                 this.get(UEP.BASE).one('.'+CSS.SEARCHOPTIONS+' .'+CSS.COLLAPSIBLEAREA).toggleClass(CSS.HIDDEN);
index 093a58a..cbde453 100644 (file)
@@ -113,7 +113,7 @@ YUI.add('moodle-enrol-rolemanager', function(Y) {
             var event = this.on('assignablerolesloaded', function(){
                 event.detach();
                 var s = M.str.role, confirmation = {
-                    lightbox :  true,
+                    modal:  true,
                     visible  :  true,
                     centered :  true,
                     title    :  s.confirmunassigntitle,
index c5beda0..0a18679 100644 (file)
Binary files a/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-debug.js and b/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-debug.js differ
index 605f8f5..5d6f83b 100644 (file)
Binary files a/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-min.js and b/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker-min.js differ
index c5beda0..0a18679 100644 (file)
Binary files a/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker.js and b/filter/glossary/yui/build/moodle-filter_glossary-autolinker/moodle-filter_glossary-autolinker.js differ
index efee206..3217f4a 100644 (file)
@@ -68,7 +68,7 @@ Y.extend(AUTOLINKER, Y.Base, {
                 for (key in data.entries) {
                     definition = data.entries[key].definition + data.entries[key].attachments;
                     alertpanel = new M.core.alert({title:data.entries[key].concept,
-                        message:definition, lightbox:false, yesLabel: M.util.get_string('ok', 'moodle')});
+                        message:definition, modal:false, yesLabel: M.util.get_string('ok', 'moodle')});
                     alertpanel.show();
                     Y.Node.one('#id_yuialertconfirm-' + alertpanel.get('COUNT')).focus();
                 }
index 290e7ed..538d03e 100644 (file)
@@ -132,8 +132,13 @@ class filter_urltolink extends moodle_text_filter {
         $querystring = '(?:\?(?:[\pL0-9\.!$&\'\(\)*+,;=_~:@/?-]|%[a-fA-F0-9]{2})*)';
         $fragment = '(?:\#(?:[\pL0-9\.!$&\'\(\)*+,;=_~:@/?-]|%[a-fA-F0-9]{2})*)';
 
-        $regex = "(?<!=[\"'])$urlstart((?:$domainsegment\.)+$domainsegment|$numericip)" .
-                "($port?$path$querystring?$fragment?)(?<![]),.;])";
+        // Lookbehind assertions.
+        // Is not HTML attribute or CSS URL property. Unfortunately legit text like "url(http://...)" will not be a link.
+        $lookbehindstart = "(?<!=[\"']|\burl\([\"' ]|\burl\()";
+        $lookbehindend = "(?<![]),.;])";
+
+        $regex = "$lookbehindstart$urlstart((?:$domainsegment\.)+$domainsegment|$numericip)" .
+                "($port?$path$querystring?$fragment?)$lookbehindend";
         if ($unicoderegexp) {
             $regex = '#' . $regex . '#ui';
         } else {
index e448d26..58bd4a3 100644 (file)
@@ -31,19 +31,6 @@ require_once($CFG->dirroot . '/filter/urltolink/filter.php'); // Include the cod
 
 class filter_urltolink_testcase extends basic_testcase {
 
-    /**
-     * Helper function that represents the legacy implementation
-     * of convert_urls_into_links()
-     */
-    protected function old_convert_urls_into_links(&$text) {
-        /// Make lone URLs into links.   eg http://moodle.com/
-        $text = preg_replace("%([[:space:]]|^|\(|\[)([[:alnum:]]+)://([^[:space:]]*)([[:alnum:]#?/&=])%i",
-            '$1<a href="$2://$3$4" target="_blank">$2://$3$4</a>', $text);
-        /// eg www.moodle.com
-        $text = preg_replace("%([[:space:]]|^|\(|\[)www\.([^[:space:]]*)([[:alnum:]#?/&=])%i",
-            '$1<a href="http://www.$2$3" target="_blank">www.$2$3</a>', $text);
-    }
-
     function get_convert_urls_into_links_test_cases() {
         $texts = array (
             //just a url
@@ -144,6 +131,11 @@ class filter_urltolink_testcase extends basic_testcase {
             '<td background="www.moodle.org">&nbsp;</td>' => '<td background="www.moodle.org">&nbsp;</td>',
             '<form name="input" action="http://moodle.org/submit.asp" method="get">'=>'<form name="input" action="http://moodle.org/submit.asp" method="get">',
             '<td background="https://www.moodle.org">&nbsp;</td>' => '<td background="https://www.moodle.org">&nbsp;</td>',
+            // CSS URLs.
+            '<table style="background-image: url(\'http://moodle.org/pic.jpg\');">' => '<table style="background-image: url(\'http://moodle.org/pic.jpg\');">',
+            '<table style="background-image: url(http://moodle.org/pic.jpg);">' => '<table style="background-image: url(http://moodle.org/pic.jpg);">',
+            '<table style="background-image: url("http://moodle.org/pic.jpg");">' => '<table style="background-image: url("http://moodle.org/pic.jpg");">',
+            '<table style="background-image: url( http://moodle.org/pic.jpg );">' => '<table style="background-image: url( http://moodle.org/pic.jpg );">',
             //partially escaped img tag
             'partially escaped img tag &lt;img src="http://moodle.org/logo/logo-240x60.gif" />' => 'partially escaped img tag &lt;img src="http://moodle.org/logo/logo-240x60.gif" />',
             //fully escaped img tag. Commented out as part of MDL-21183
@@ -181,32 +173,6 @@ class filter_urltolink_testcase extends basic_testcase {
         $this->assertEquals($correctresult, $text);
     }
 
-    function test_convert_urls_into_links_performance() {
-        $testablefilter = new testable_filter_urltolink();
-
-        $reps = 1000;
-        $text = file_get_contents(__DIR__ . '/fixtures/sample.txt');
-        $time_start = microtime(true);
-        for($i=0;$i<$reps;$i++) {
-            $testablefilter->convert_urls_into_links($text);
-        }
-        $time_end = microtime(true);
-        $new_time = $time_end - $time_start;
-
-        $time_start = microtime(true);
-        for($i=0;$i<$reps;$i++) {
-            $this->old_convert_urls_into_links($text);
-        }
-        $time_end = microtime(true);
-        $old_time = $time_end - $time_start;
-
-        $fast_enough = false;
-        if( $new_time < $old_time ) {
-            $fast_enough = true;
-        }
-
-        $this->assertEquals($fast_enough, true, 'Timing test: ' . $new_time . 'secs (new) < ' . $old_time . 'secs (old)');
-    }
 }
 
 
index 0c250a0..c7f4fc5 100644 (file)
@@ -60,10 +60,10 @@ if (function_exists('date_default_timezone_set') and function_exists('date_defau
 @ini_set('display_errors', '1');
 
 // Check that PHP is of a sufficient version.
-if (version_compare(phpversion(), '5.3.3') < 0) {
+if (version_compare(phpversion(), '5.4.4') < 0) {
     $phpversion = phpversion();
     // do NOT localise - lang strings would not work here and we CAN not move it after installib
-    echo "Moodle 2.5 or later requires at least PHP 5.3.3 (currently using version $phpversion).<br />";
+    echo "Moodle 2.7 or later requires at least PHP 5.4.4 (currently using version $phpversion).<br />";
     echo "Please upgrade your server software or install older Moodle version.";
     die;
 }
@@ -530,11 +530,10 @@ if ($config->stage == INSTALL_DATABASETYPE) {
 
 
 if ($config->stage == INSTALL_ENVIRONMENT or $config->stage == INSTALL_PATHS) {
-    $version_fail = (version_compare(phpversion(), "5.3.3") < 0);
     $curl_fail    = ($lang !== 'en' and !extension_loaded('curl')); // needed for lang pack download
     $zip_fail     = ($lang !== 'en' and !extension_loaded('zip'));  // needed for lang pack download
 
-    if ($version_fail or $curl_fail or $zip_fail) {
+    if ($curl_fail or $zip_fail) {
         $config->stage = INSTALL_ENVIRONMENT;
 
         install_print_header($config, get_string('environmenthead', 'install'),
@@ -542,10 +541,6 @@ if ($config->stage == INSTALL_ENVIRONMENT or $config->stage == INSTALL_PATHS) {
                                       get_string('environmentsub2', 'install'));
 
         echo '<div id="envresult"><dl>';
-        if ($version_fail) {
-            $a = (object)array('needed'=>'5.3.3', 'current'=>phpversion());
-            echo '<dt>'.get_string('phpversion', 'install').'</dt><dd>'.get_string('environmentrequireversion', 'admin', $a).'</dd>';
-        }
         if ($curl_fail) {
             echo '<dt>'.get_string('phpextension', 'install', 'cURL').'</dt><dd>'.get_string('environmentrequireinstall', 'admin').'</dd>';
         }
index 954c712..eba828b 100644 (file)
@@ -30,7 +30,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$string['cannotcreatedboninstall'] = '<p>Non è possibile creare il database </p> <p>Il database non esiste o l\'utente non è autorizzato a crearlo.</p>
+$string['cannotcreatedboninstall'] = '<p>Non è possibile creare il database </p> <p>Il database non esiste e l\'utente fornito non è autorizzato a crearlo.</p>
 <p>E\' necessario che l\'amministratore del sito  verifichi  la configurazione del database.</p>';
 $string['cannotcreatelangdir'] = 'Non è possibile creare la cartella lang';
 $string['cannotcreatetempdir'] = 'Non è possibile creare la cartella temp';
index e678417..56d14f3 100644 (file)
@@ -30,6 +30,9 @@
 
 defined('MOODLE_INTERNAL') || die();
 
+$string['cannotcreatedboninstall'] = '<p>無法建立資料庫</p>
+<p>指定之資料庫並不存在。使用者並未有權限建立資料庫</p>
+<p>網站管理員需查明資料庫之組態.</p>';
 $string['cannotcreatelangdir'] = '無法建立語言資料夾。';
 $string['cannotcreatetempdir'] = '無法建立暫存資料夾。';
 $string['cannotdownloadcomponents'] = '無法下載元件。';
index f2f102a..0f537a4 100644 (file)
@@ -372,12 +372,14 @@ $string['courserequestsupport'] = 'Supporting information to help the administra
 $string['courserestore'] = 'Course restore';
 $string['courses'] = 'Courses';
 $string['coursesectionsummaries'] = 'Course section summaries';
+$string['coursesectiontitle'] = 'Course: {$a->course}, {$a->sectionname}: {$a->sectiontitle}';
 $string['coursesettings'] = 'Course default settings';
 $string['coursesmovedout'] = 'Courses moved out from {$a}';
 $string['coursespending'] = 'Courses pending approval';
 $string['coursestart'] = 'Course start';
 $string['coursesummary'] = 'Course summary';
 $string['coursesummary_help'] = 'The course summary is displayed in the list of courses. A course search searches course summary text in addition to course names.';
+$string['coursetitle'] = 'Course: {$a->course}';
 $string['courseupdates'] = 'Course updates';
 $string['create'] = 'Create';
 $string['createaccount'] = 'Create my new account';
index f035ae7..8e92faf 100644 (file)
@@ -5462,6 +5462,10 @@ abstract class context extends stdClass implements IteratorAggregate {
     public function delete() {
         global $DB;
 
+        if ($this->_contextlevel <= CONTEXT_SYSTEM) {
+            throw new coding_exception('Cannot delete system context');
+        }
+
         // double check the context still exists
         if (!$DB->record_exists('context', array('id'=>$this->_id))) {
             context::cache_remove($this);
@@ -5557,6 +5561,11 @@ abstract class context extends stdClass implements IteratorAggregate {
     public function get_child_contexts() {
         global $DB;
 
+        if (empty($this->_path) or empty($this->_depth)) {
+            debugging('Can not find child contexts of context '.$this->_id.' try rebuilding of context paths');
+            return array();
+        }
+
         $sql = "SELECT ctx.*
                   FROM {context} ctx
                  WHERE ctx.path LIKE ?";
@@ -6557,6 +6566,11 @@ class context_coursecat extends context {
     public function get_child_contexts() {
         global $DB;
 
+        if (empty($this->_path) or empty($this->_depth)) {
+            debugging('Can not find child contexts of context '.$this->_id.' try rebuilding of context paths');
+            return array();
+        }
+
         $sql = "SELECT ctx.*
                   FROM {context} ctx
                  WHERE ctx.path LIKE ? AND (ctx.depth = ? OR ctx.contextlevel = ?)";
index d0c2695..11b5ef2 100644 (file)
                                die("Illegal path http:// or ftp://");
                }
                
-                       
-               // Initialize random number generator for randomizing cache flushes
-               // -- note Since PHP 4.2.0, the seed  becomes optional and defaults to a random value if omitted.
-                srand(((double)microtime())*1000000);
-               
                /**
                 * ADODB version as a string.
                 */
index aee9248..27ff1b5 100644 (file)
@@ -19,6 +19,6 @@ Added:
  * readme_moodle.txt - this file ;-)
 
 Our changes:
- * none
+ * Removed random seed initialization from lib/adodb/adodb.inc.php:172
 
 skodak, iarenaza, moodler, stronk7
index c57e6c0..c9f21f8 100644 (file)
@@ -67,3 +67,40 @@ function ajaxenabled(array $browsers = null) {
         return false;
     }
 }
+
+/**
+ * Starts capturing output whilst processing an AJAX request.
+ *
+ * This should be used in combination with ajax_check_captured_output to
+ * report any captured output to the user.
+ *
+ * @retrun Boolean Returns true on success or false on failure.
+ */
+function ajax_capture_output() {
+    // Start capturing output in case of broken plugins.
+    return ob_start();
+}
+
+/**
+ * Check captured output for content. If the site has a debug level of
+ * debugdeveloper set, and the content is non-empty, then throw a coding
+ * exception which can be captured by the Y.IO request and displayed to the
+ * user.
+ *
+ * @return Any output that was captured.
+ */
+function ajax_check_captured_output() {
+    global $CFG;
+
+    // Retrieve the output - there should be none.
+    $output = ob_get_contents();
+    ob_end_clean();
+
+    if ($CFG->debugdeveloper && !empty($output)) {
+        // Only throw an error if the site is in debugdeveloper.
+        throw new coding_exception('Unexpected output whilst processing AJAX request. ' .
+                'This could be caused by trailing whitespace. Output received: ' .
+                var_export($output, true));
+    }
+    return $output;
+}
index 9f7d940..459d1c3 100644 (file)
@@ -40,7 +40,7 @@ if ($branchtype !== navigation_node::TYPE_SITE_ADMIN) {
 }
 
 // Start capturing output in case of broken plugins.
-ob_start();
+ajax_capture_output();
 
 $PAGE->set_context(context_system::instance());
 $PAGE->set_url('/lib/ajax/getsiteadminbranch.php', array('type'=>$branchtype));
@@ -51,12 +51,5 @@ $sitenavigation = new settings_navigation_ajax($PAGE);
 $converter = new navigation_json();
 $branch = $sitenavigation->get('root');
 
-$output = ob_get_contents();
-ob_end_clean();
-if ($CFG->debugdeveloper && !empty($output)) {
-    throw new coding_exception('Unexpected output whilst building the administration tree. ' .
-            'This could be caused by trailing whitespace. Output received: ' .
-            var_export($output, true));
-} else {
-    echo $converter->convert($branch);
-}
+ajax_check_captured_output();
+echo $converter->convert($branch);
index 57c86fa..8d1bf9e 100644 (file)
@@ -429,51 +429,63 @@ class badge {
         core_php_time_limit::raise();
         raise_memory_limit(MEMORY_HUGE);
 
-        // For site level badges, get all active site users who can earn this badge and haven't got it yet.
-        if ($this->type == BADGE_TYPE_SITE) {
-            $sql = 'SELECT DISTINCT u.id, bi.badgeid
+        foreach ($this->criteria as $crit) {
+            // Overall criterion is decided when other criteria are reviewed.
+            if ($crit->criteriatype == BADGE_CRITERIA_TYPE_OVERALL) {
+                continue;
+            }
+
+            list($extrajoin, $extrawhere, $extraparams) = $crit->get_completed_criteria_sql();
+            // For site level badges, get all active site users who can earn this badge and haven't got it yet.
+            if ($this->type == BADGE_TYPE_SITE) {
+                $sql = "SELECT DISTINCT u.id, bi.badgeid
                         FROM {user} u
+                        {$extrajoin}
                         LEFT JOIN {badge_issued} bi
                             ON u.id = bi.userid AND bi.badgeid = :badgeid
-                        WHERE bi.badgeid IS NULL AND u.id != :guestid AND u.deleted = 0';
-            $toearn = $DB->get_fieldset_sql($sql, array('badgeid' => $this->id, 'guestid' => $CFG->siteguest));
-        } else {
-            // For course level badges, get users who can earn this badge in the course.
-            // These are all enrolled users with capability moodle/badges:earnbadge.
-            $earned = $DB->get_fieldset_select('badge_issued', 'userid AS id', 'badgeid = :badgeid', array('badgeid' => $this->id));
-            $users = get_enrolled_users($this->get_context(), 'moodle/badges:earnbadge', 0, 'u.id');
-            $toearn = array_diff(array_keys($users), $earned);
-        }
+                        WHERE bi.badgeid IS NULL AND u.id != :guestid AND u.deleted = 0 " . $extrawhere;
+                $params = array_merge(array('badgeid' => $this->id, 'guestid' => $CFG->siteguest), $extraparams);
+                $toearn = $DB->get_fieldset_sql($sql, $params);
+            } else {
+                // For course level badges, get all users who already earned the badge in this course.
+                // Then find the ones who are enrolled in the course and don't have a badge yet.
+                $earned = $DB->get_fieldset_select('badge_issued', 'userid AS id', 'badgeid = :badgeid', array('badgeid' => $this->id));
+                $wheresql = '';
+                $earnedparams = array();
+                if (!empty($earned)) {
+                    list($earnedsql, $earnedparams) = $DB->get_in_or_equal($earned, SQL_PARAMS_NAMED, 'u', false);
+                    $wheresql = ' WHERE u.id ' . $earnedsql;
+                }
+                list($enrolledsql, $enrolledparams) = get_enrolled_sql($this->get_context(), 'moodle/badges:earnbadge', 0, true);
+                $sql = "SELECT u.id
+                        FROM {user} u
+                        {$extrajoin}
+                        JOIN ({$enrolledsql}) je ON je.id = u.id " . $wheresql . $extrawhere;
+                $params = array_merge($enrolledparams, $earnedparams, $extraparams);
+                $toearn = $DB->get_fieldset_sql($sql, $params);
+            }
 
-        foreach ($toearn as $uid) {
-            $toreview = false;
-            foreach ($this->criteria as $crit) {
-                if ($crit->criteriatype != BADGE_CRITERIA_TYPE_OVERALL) {
-                    if ($crit->review($uid)) {
-                        $crit->mark_complete($uid);
-                        if ($this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->method == BADGE_CRITERIA_AGGREGATION_ANY) {
-                            $this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($uid);
-                            $this->issue($uid);
-                            $awards++;
-                            break;
-                        } else {
-                            $toreview = true;
-                            continue;
-                        }
+            foreach ($toearn as $uid) {
+                $reviewoverall = false;
+                if ($crit->review($uid, true)) {
+                    $crit->mark_complete($uid);
+                    if ($this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->method == BADGE_CRITERIA_AGGREGATION_ANY) {
+                        $this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($uid);
+                        $this->issue($uid);
+                        $awards++;
                     } else {
-                        if ($this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->method == BADGE_CRITERIA_AGGREGATION_ANY) {
-                            continue;
-                        } else {
-                            break;
-                        }
+                        $reviewoverall = true;
                     }
+                } else {
+                    // Will be reviewed some other time.
+                    $reviewoverall = false;
+                }
+                // Review overall if it is required.
+                if ($reviewoverall && $this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($uid)) {
+                    $this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($uid);
+                    $this->issue($uid);
+                    $awards++;
                 }
-            }
-            // Review overall if it is required.
-            if ($toreview && $this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->review($uid)) {
-                $this->criteria[BADGE_CRITERIA_TYPE_OVERALL]->mark_complete($uid);
-                $this->issue($uid);
-                $awards++;
             }
         }
 
index 20762ae..619dcd6 100644 (file)
@@ -100,18 +100,11 @@ class behat_command {
      * It checks behat dependencies have been installed and runs
      * the behat help command to ensure it works as expected
      *
-     * @param  bool $checkphp Extra check for the PHP version
      * @return int Error code or 0 if all ok
      */
-    public static function behat_setup_problem($checkphp = false) {
+    public static function behat_setup_problem() {
         global $CFG;
 
-        // We don't check the PHP version if $CFG->behat_switchcompletely has been enabled.
-        // Here we are in CLI.
-        if (empty($CFG->behat_switchcompletely) && empty($CFG->behat_wwwroot) && $checkphp && version_compare(PHP_VERSION, '5.4.0', '<')) {
-            behat_error(BEHAT_EXITCODE_REQUIREMENT, 'PHP 5.4 is required. See config-dist.php for possible alternatives');
-        }
-
         $clibehaterrorstr = "Behat dependencies not installed. Ensure you ran the composer installer. " . self::DOCS_URL . "#Installation\n";
 
         // Moodle setting.
@@ -148,7 +141,9 @@ class behat_command {
         }
 
         // Checking behat dataroot existence otherwise echo about admin/tool/behat/cli/init.php.
-        $CFG->behat_dataroot = realpath($CFG->behat_dataroot);
+        if (!empty($CFG->behat_dataroot)) {
+            $CFG->behat_dataroot = realpath($CFG->behat_dataroot);
+        }
         if (empty($CFG->behat_dataroot) || !is_dir($CFG->behat_dataroot) || !is_writable($CFG->behat_dataroot)) {
             self::output_msg(get_string('runclitool', 'tool_behat', 'php admin/tool/behat/cli/init.php'));
             return BEHAT_EXITCODE_CONFIG;
index d559ff4..a967cad 100644 (file)
@@ -183,6 +183,11 @@ class behat_config_manager {
         // We require here when we are sure behat dependencies are available.
         require_once($CFG->dirroot . '/vendor/autoload.php');
 
+        // It is possible that it has no value as we don't require a full behat setup to list the step definitions.
+        if (empty($CFG->behat_wwwroot)) {
+            $CFG->behat_wwwroot = 'http://itwillnotbeused.com';
+        }
+
         $basedir = $CFG->dirroot . DIRECTORY_SEPARATOR . 'lib' . DIRECTORY_SEPARATOR . 'behat';
         $config = array(
             'default' => array(
index c8504fe..ca16c26 100644 (file)
@@ -102,7 +102,10 @@ class behat_util extends testing_util {
 
         // Sets maximum debug level.
         set_config('debug', DEBUG_DEVELOPER);
-        set_config('debugdisplay', true);
+        set_config('debugdisplay', 1);
+
+        // Disable some settings that are not wanted on test sites.
+        set_config('noemailever', 1);
 
         // Keeps the current version of database and dataroot.
         self::store_versions_hash();
@@ -181,7 +184,7 @@ class behat_util extends testing_util {
      * features and steps definitions.
      *
      * Stores a file in dataroot/behat to allow Moodle to switch
-     * to the test environment when using cli-server (or $CFG->behat_switchcompletely)
+     * to the test environment when using cli-server.
      * @throws coding_exception
      * @return void
      */
@@ -193,7 +196,7 @@ class behat_util extends testing_util {
         }
 
         // Checks the behat set up and the PHP version.
-        if ($errorcode = behat_command::behat_setup_problem(true)) {
+        if ($errorcode = behat_command::behat_setup_problem()) {
             exit($errorcode);
         }
 
@@ -227,7 +230,7 @@ class behat_util extends testing_util {
         }
 
         // Checks the behat set up and the PHP version, returning an error code if something went wrong.
-        if ($errorcode = behat_command::behat_setup_problem(true)) {
+        if ($errorcode = behat_command::behat_setup_problem()) {
             return $errorcode;
         }
 
index 667125e..74d45cf 100644 (file)
@@ -153,9 +153,9 @@ function behat_clean_init_config() {
 
     $allowed = array_flip(array(
         'wwwroot', 'dataroot', 'dirroot', 'admin', 'directorypermissions', 'filepermissions',
-        'dbtype', 'dblibrary', 'dbhost', 'dbname', 'dbuser', 'dbpass', 'prefix', 'dboptions',
-        'proxyhost', 'proxyport', 'proxytype', 'proxyuser', 'proxypassword', 'proxybypass',
-        'theme'
+        'umaskpermissions', 'dbtype', 'dblibrary', 'dbhost', 'dbname', 'dbuser', 'dbpass', 'prefix',
+        'dboptions', 'proxyhost', 'proxyport', 'proxytype', 'proxyuser', 'proxypassword',
+        'proxybypass', 'theme'
     ));
 
     // Add extra allowed settings.
@@ -180,56 +180,81 @@ function behat_clean_init_config() {
 function behat_check_config_vars() {
     global $CFG;
 
-    // CFG->behat_prefix must be set and with value different than CFG->prefix and phpunit_prefix.
-    if (empty($CFG->behat_prefix) ||
-           ($CFG->behat_prefix == $CFG->prefix) ||
-           (!empty($CFG->phpunit_prefix) && $CFG->behat_prefix == $CFG->phpunit_prefix)) {
+    // Verify prefix value.
+    if (empty($CFG->behat_prefix)) {
         behat_error(BEHAT_EXITCODE_CONFIG,
-            'Define $CFG->behat_prefix in config.php with a value different than $CFG->prefix and $CFG->phpunit_prefix');
+            'Define $CFG->behat_prefix in config.php');
     }
-
-    // $CFG->behat_wwwroot must be different than CFG->wwwroot if it is set, it may not be set as
-    // it can take the default value and we should also consider that will have the same value than
-    // $CFG->wwwroot if $CFG->behat_switchcompletely is set.
-    if (!empty($CFG->behat_wwwroot) && $CFG->behat_wwwroot == $CFG->wwwroot && empty($CFG->behat_switchcompletely)) {
+    if (!empty($CFG->prefix) and $CFG->behat_prefix == $CFG->prefix) {
+        behat_error(BEHAT_EXITCODE_CONFIG,
+            '$CFG->behat_prefix in config.php must be different from $CFG->prefix');
+    }
+    if (!empty($CFG->phpunit_prefix) and $CFG->behat_prefix == $CFG->phpunit_prefix) {
         behat_error(BEHAT_EXITCODE_CONFIG,
-            'Define $CFG->behat_wwwroot in config.php with a value different than $CFG->wwwroot');
+            '$CFG->behat_prefix in config.php must be different from $CFG->phpunit_prefix');
     }
 
-    // CFG->behat_dataroot must be set and with value different than CFG->dataroot and phpunit_dataroot.
-    $CFG->dataroot = realpath($CFG->dataroot);
-    if (!empty($CFG->behat_dataroot) && is_dir($CFG->behat_dataroot)) {
-        $CFG->behat_dataroot = realpath($CFG->behat_dataroot);
+    // Verify behat wwwroot value.
+    if (empty($CFG->behat_wwwroot)) {
+        behat_error(BEHAT_EXITCODE_CONFIG,
+            'Define $CFG->behat_wwwroot in config.php');
     }
-    if (empty($CFG->behat_dataroot) ||
-           ($CFG->behat_dataroot == $CFG->dataroot) ||
-           (!empty($CFG->phpunit_dataroot) && is_dir($CFG->phpunit_dataroot)
-                && $CFG->behat_dataroot == realpath($CFG->phpunit_dataroot))) {
+    if (!empty($CFG->wwwroot) and $CFG->behat_wwwroot == $CFG->wwwroot) {
         behat_error(BEHAT_EXITCODE_CONFIG,
-            'Define $CFG->behat_dataroot in config.php with a value different than $CFG->dataroot and $CFG->phpunit_dataroot');
+            '$CFG->behat_wwwroot in config.php must be different from $CFG->wwwroot');
     }
 
+    // Verify behat dataroot value.
+    if (empty($CFG->behat_dataroot)) {
+        behat_error(BEHAT_EXITCODE_CONFIG,
+            'Define $CFG->behat_dataroot in config.php');
+    }
+    if (!file_exists($CFG->behat_dataroot)) {
+        $permissions = isset($CFG->directorypermissions) ? $CFG->directorypermissions : 02777;
+        umask(0);
+        if (!mkdir($CFG->behat_dataroot, $permissions, true)) {
+            behat_error(BEHAT_EXITCODE_PERMISSIONS, '$CFG->behat_dataroot directory can not be created');
+        }
+    }
+    $CFG->behat_dataroot = realpath($CFG->behat_dataroot);
+    if (empty($CFG->behat_dataroot) or !is_dir($CFG->behat_dataroot) or !is_writable($CFG->behat_dataroot)) {
+        behat_error(BEHAT_EXITCODE_CONFIG,
+            '$CFG->behat_dataroot in config.php must point to an existing writable directory');
+    }
+    if (!empty($CFG->dataroot) and $CFG->behat_dataroot == realpath($CFG->dataroot)) {
+        behat_error(BEHAT_EXITCODE_CONFIG,
+            '$CFG->behat_dataroot in config.php must be different from $CFG->dataroot');
+    }
+    if (!empty($CFG->phpunit_dataroot) and $CFG->behat_dataroot == realpath($CFG->phpunit_dataroot)) {
+        behat_error(BEHAT_EXITCODE_CONFIG,
+            '$CFG->behat_dataroot in config.php must be different from $CFG->phpunit_dataroot');
+    }
 }
 
 /**
- * Returns a URL based on the priorities between $CFG->behat_* vars.
- *
- * 1.- Switch completely wins and overwrites behat_wwwroot
- * 2.- behat_wwwroot alternatively
- * 3.- http://localhost:8000 if there is nothing else
- *
- * @return string
+ * Should we switch to the test site data?
+ * @return bool
  */
-function behat_get_wwwroot() {
+function behat_is_test_site() {
     global $CFG;
 
-    if (!empty($CFG->behat_switchcompletely)) {
-        return $CFG->wwwroot;
-    } else if (!empty($CFG->behat_wwwroot)) {
-        return $CFG->behat_wwwroot;
+    if (defined('BEHAT_UTIL')) {
+        // This is the admin tool that installs/drops the test site install.
+        return true;
+    }
+    if (defined('BEHAT_TEST')) {
+        // This is the main vendor/bin/behat script.
+        return true;
+    }
+    if (empty($CFG->behat_wwwroot)) {
+        return false;
+    }
+    if (isset($_SERVER['REMOTE_ADDR']) and behat_is_requested_url($CFG->behat_wwwroot)) {
+        // Something is accessing the web server like a real browser.
+        return true;
     }
 
-    return 'http://localhost:8000';
+    return false;
 }
 
 /**
index 4e4ed8d..46aa825 100644 (file)
@@ -36,6 +36,13 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Both events could be triggered in a row, first the uploaded, then the submitted.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type array pathnamehashes uploaded files path name hashes.
+ *      @type string content string.
+ * }
+ *
  * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 5670f52..0e7da1c 100644 (file)
@@ -29,6 +29,15 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when a new blog entry is associated with a context.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string associatetype type of blog association, course/coursemodule.
+ *      @type int blogid id of blog.
+ *      @type int associateid id of associate.
+ *      @type string subject blog subject.
+ * }
+ *
  * @package    core
  * @copyright  2013 onwards Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index bf4dbaf..d0119fa 100644 (file)
@@ -29,6 +29,12 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when blog entries are viewed.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int courseid id of associated course.
+ * }
+ *
  * @package    core
  * @copyright  2013 onwards Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index abee52e..cebf7c5 100644 (file)
@@ -31,6 +31,12 @@ defined('MOODLE_INTERNAL') || die();
  *
  * This class has to be extended by any event which is triggred while creating new comment.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int itemid id of item for which comment is added.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index f6a2004..69c43c6 100644 (file)
@@ -31,6 +31,12 @@ defined('MOODLE_INTERNAL') || die();
  *
  * This class has to be extended by any event which is triggred while deleting comment.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int itemid id of item for which comment is deleted.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 7492bd1..17f0328 100644 (file)
@@ -39,6 +39,12 @@ defined('MOODLE_INTERNAL') || die();
  *  $event->trigger();
  * where \report_participation\event\content_viewed extends \core\event\content_viewed
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string content viewed content identifier.
+ * }
+ *
  * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index ff7ecf3..a856ef1 100644 (file)
@@ -19,7 +19,13 @@ namespace core\event;
 defined('MOODLE_INTERNAL') || die();
 
 /**
- * category deleted event.
+ * Category deleted event.
+ *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string name category name.
+ * }
  *
  * @package    core
  * @copyright  2013 Mark Nelson <markn@moodle.com>
index 92fc9a6..d5b6624 100644 (file)
@@ -21,6 +21,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Course content_deleted event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type array options list of options which were skipped while deleting course content.
+ * }
+ *
  * @package    core
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index deeacb4..57eb640 100644 (file)
@@ -21,6 +21,13 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Course created event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string shortname shortname of course.
+ *      @type string fullname fullname of course.
+ * }
+ *
  * @package    core
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 0f704a7..0580e7c 100644 (file)
@@ -21,6 +21,14 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Course deleted event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string shortname shortname of course.
+ *      @type string fullname fullname of course.
+ *      @type string idnumber id number of course.
+ * }
+ *
  * @package    core
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 9ed6fc8..2c481a8 100644 (file)
 /**
  * Event to be triggered when a new course module is created.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string modulename name of module created.
+ *      @type string name title of module.
+ *      @type string instanceid id of module instance.
+ * }
+ *
  * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
index 67a4b02..d00a43a 100644 (file)
@@ -30,6 +30,13 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when a course module is deleted.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string modulename name of module deleted.
+ *      @type string instanceid id of module instance.
+ * }
+ *
  * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
index ced4210..99e61f8 100644 (file)
@@ -30,6 +30,14 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when a course module is updated.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string modulename name of module updated.
+ *      @type string name title of module.
+ *      @type string instanceid id of module instance.
+ * }
+ *
  * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later.
index 56e1009..5c8f280 100644 (file)
@@ -28,6 +28,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * core course reset ended event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type array reset_options all reset options settings including courseid.
+ * }
+ *
  * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 8a34a75..f28d6de 100644 (file)
@@ -28,6 +28,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * core course reset started event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type array reset_options all reset options settings including courseid.
+ * }
+ *
  * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 2f8fa4f..8e7af36 100644 (file)
@@ -21,6 +21,16 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Course restored event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string type restore type, activity, course or section.
+ *      @type int target where restored (new/existing/current/adding/deleting)
+ *      @type int mode execution mode
+ *      @type string opertaion restore
+ *      @type boolean samesite true is restored to same site.
+ * }
+ *
  * @package    core
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 5a7d9e0..60760e5 100644 (file)
@@ -29,6 +29,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Course section updated.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int sectionnum section number.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index c037d20..47ab3af 100644 (file)
@@ -21,6 +21,13 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Course updated event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string shortname shortname of course.
+ *      @type string fullname fullname of course.
+ * }
+ *
  * @package    core
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index df1c2d1..6855e15 100644 (file)
@@ -28,6 +28,13 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * core_group member added event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string component name of component
+ *      @type int itemid id of item.
+ * }
+ *
  * @package    core_group
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 838ba8c..e3ce2ab 100644 (file)
@@ -31,6 +31,12 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when a note is created.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string publishstate publish state.
+ * }
+ *
  * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 45249fe..52f9182 100644 (file)
@@ -31,6 +31,12 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when a note is deleted.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string publishstate publish state
+ * }
+ *
  * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index df3ac78..fb94617 100644 (file)
@@ -31,6 +31,12 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when a note is updated.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string publishstate publish state.
+ * }
+ *
  * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 3680fc4..a298106 100644 (file)
@@ -31,6 +31,12 @@ defined('MOODLE_INTERNAL') || die();
  *
  * Class for event to be triggered when a note is viewed.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string content hard-coded to notes.
+ * }
+ *
  * @package    core
  * @copyright  2013 Ankit Agarwal
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 5213900..f22fd16 100644 (file)
@@ -21,6 +21,14 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Role assigned event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int id role assigned id.
+ *      @type string component name of component.
+ *      @type int itemid id of item.
+ * }
+ *
  * @package    core
  * @copyright  2013 Petr Skoda {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index d11dab8..ae150c8 100644 (file)
@@ -21,6 +21,14 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Role assigned event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string shortname shortname of role.
+ *      @type string description role description.
+ *      @type string archetype role type.
+ * }
+ *
  * @package    core_event
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 2e5a986..f3d0850 100644 (file)
@@ -21,6 +21,14 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Role unassigned event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int id role assigned id.
+ *      @type string component name of component.
+ *      @type int itemid id of item.
+ * }
+ *
  * @package    core
  * @copyright  2013 Petr Skoda {@link http://skodak.org}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index e04ee16..fdc68c8 100644 (file)
@@ -28,6 +28,16 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Event when user profile is deleted.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string username name of user.
+ *      @type string email user email.
+ *      @type string idnumber user idnumber.
+ *      @type string picture user picture.
+ *      @type int mnethostid mnet host id.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 064ccf5..c5e0d0e 100644 (file)
@@ -28,6 +28,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Event when user is enrolled in a course.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string enrol name of enrolment instance.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 8992347..4376a2b 100644 (file)
 /**
  * User enrolment deleted event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string enrol name of enrolment instance.
+ *      @type array userenrolment user_enrolment record.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 8e53236..69e71de 100644 (file)
@@ -28,6 +28,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Event when user enrolment is updated.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string enrol name of enrolment instance.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 45aa787..fce1f0d 100644 (file)
 /**
  * Defines the user list viewed event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int courseid id of course.
+ *      @type string courseshortname short name of course.
+ *      @type string coursefullname full name of course.
+ * }
+ *
  * @package    core
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 9628e31..0bb4e17 100644 (file)
@@ -29,6 +29,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * User login event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string username name of user.
+ * }
+ *
  * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 50012d8..136307d 100644 (file)
@@ -29,6 +29,13 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * User loggedinas event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string originalusername original username.
+ *      @type string loggedinasusername username of logged in as user.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 8f2c6aa..d17f0bf 100644 (file)
@@ -28,6 +28,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * Event when user logout.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string sessionid session id.
+ * }
+ *
  * @package    core
  * @copyright  2013 Rajesh Taneja <rajesh@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index af9f228..eefc9bf 100644 (file)
 /**
  * Defines the user profile viewed event.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type int courseid id of course.
+ *      @type string courseshortname short name of course.
+ *      @type string coursefullname fullname of course.
+ * }
+ *
  * @package    core
  * @copyright  2013 Mark Nelson <markn@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 9914385..1334784 100644 (file)
@@ -28,6 +28,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * core webservice function_called event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string function name of the function.
+ * }
+ *
  * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 395e91b..9ababb0 100644 (file)
@@ -28,6 +28,14 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * core web service login_failed event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string method authentication method.
+ *      @type string reason failure reason.
+ *      @type string tokenid id of token.
+ * }
+ *
  * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 436a236..22fd29c 100644 (file)
@@ -28,6 +28,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * core webservice service created event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type string sessionid session id.
+ * }
+ *
  * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 5f18336..d5799e0 100644 (file)
@@ -28,6 +28,12 @@ defined('MOODLE_INTERNAL') || die();
 /**
  * core webservice token_created event class.
  *
+ * @property-read array $other {
+ *      Extra information about event.
+ *
+ *      @type bool auto automatically created.
+ * }
+ *
  * @package    core
  * @copyright  2013 Frédéric Massart
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
index 18a0e19..49830c7 100644 (file)
@@ -66,7 +66,6 @@ function cron_run() {
     // Run cleanup core cron jobs, but not every time since they aren't too important.
     // These don't have a timer to reduce load, so we'll use a random number
     // to randomly choose the percentage of times we should run these jobs.
-    srand ((double) microtime() * 10000000);
     $random100 = rand(0,100);
     if ($random100 < 20) {     // Approximately 20% of the time.
         mtrace("Running clean-up tasks...");
index 7644a23..d5e63a9 100644 (file)
@@ -1545,6 +1545,9 @@ class core_ddl_testcase extends database_driver_testcase {
         $this->assertSame($records[1]->secondname, $this->records['test_table1'][0]->secondname);
         $this->assertSame($records[2]->intro, $this->records['test_table1'][1]->intro);
 
+        // Collect statistics about the data in the temp table.
+        $DB->update_temp_table_stats();
+
         // Drop table1.
         $dbman->drop_table($table1);
         $this->assertFalse($dbman->table_exists('test_table1'));
@@ -1558,6 +1561,9 @@ class core_ddl_testcase extends database_driver_testcase {
             $this->assertInstanceOf('ddl_table_missing_exception', $e);
         }
 
+        // Collect statistics about the data in the temp table with less tables.
+        $DB->update_temp_table_stats();
+
         // Fill/modify/delete a few table0 records.
 
         // Drop table0.
index de17fc8..4828dcf 100644 (file)
@@ -2172,6 +2172,15 @@ abstract class moodle_database {
         }
     }
 
+    /**
+     * Analyze the data in temporary tables to force statistics collection after bulk data loads.
+     *
+     * @return void
+     */
+    public function update_temp_table_stats() {
+        $this->temptables->update_stats();
+    }
+
     /**
      * Checks and returns true if transactions are supported.
      *
index 19f0c20..8a586fe 100644 (file)
@@ -22,6 +22,7 @@
  *
  *   - databases not retrieving temp tables from information schema tables (mysql)
  *   - databases using a different name schema for temp tables (like mssql).
+ *   - databases that don't collect planner stats for temp tables (like PgSQL).
  *
  * Basically it works as a simple store of created temporary tables, providing
  * some simple getters/setters methods. Each database can extend it for its own
@@ -31,9 +32,6 @@
  * and the sql_generator, so both are able to use its facilities, with the final goal
  * of doing temporary tables support 100% cross-db and transparent within the DB API.
  *
- * Only drivers needing it will use this store. Neither moodle_database (abstract) or
- * databases like postgres need this, because they don't lack any temp functionality.
- *
  * @package    core_dml
  * @copyright  2009 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
@@ -119,6 +117,17 @@ class moodle_temptables {
         return null;
     }
 
+    /**
+     * Analyze the data in temporary tables to force statistics collection after bulk data loads.
+     * The database class detects all temporary tables and will automatically analyze all created tables
+     *
+     * @return void
+     */
+    public function update_stats() {
+        // By default most databases do automatic on temporary tables, PgSQL does not.
+        // As a result, update_stats call immediately return for non-interesting database types.
+    }
+
     /**
      * Dispose the temptables stuff, checking for wrong situations, informing and recovering from them
      */
index cc682e5..70bd6f3 100644 (file)
@@ -903,6 +903,9 @@ class mssql_native_moodle_database extends moodle_database {
         $dataobject = (array)$dataobject;
 
         $columns = $this->get_columns($table);
+        if (empty($columns)) {
+            throw new dml_exception('ddltablenotexist', $table);
+        }
         $cleaned = array();
 
         foreach ($dataobject as $field => $value) {
index 33d07b9..34320d9 100644 (file)
@@ -1106,6 +1106,10 @@ class mysqli_native_moodle_database extends moodle_database {
         $dataobject = (array)$dataobject;
 
         $columns = $this->get_columns($table);
+        if (empty($columns)) {
+            throw new dml_exception('ddltablenotexist', $table);
+        }
+
         $cleaned = array();
 
         foreach ($dataobject as $field=>$value) {
index 502a266..0c6f700 100644 (file)
@@ -1256,6 +1256,10 @@ class oci_native_moodle_database extends moodle_database {
         $dataobject = (array)$dataobject;
 
         $columns = $this->get_columns($table);
+        if (empty($columns)) {
+            throw new dml_exception('ddltablenotexist', $table);
+        }
+
         $cleaned = array();
 
         foreach ($dataobject as $field=>$value) {
index 58874bd..53fd8d5 100644 (file)
@@ -386,6 +386,10 @@ abstract class pdo_moodle_database extends moodle_database {
         $dataobject = (array)$dataobject;
 
         $columns = $this->get_columns($table);
+        if (empty($columns)) {
+            throw new dml_exception('ddltablenotexist', $table);
+        }
+
         $cleaned = array();
 
         foreach ($dataobject as $field=>$value) {
index f4cf21d..5c369a7 100644 (file)
@@ -876,6 +876,10 @@ class pgsql_native_moodle_database extends moodle_database {
         $dataobject = (array)$dataobject;
 
         $columns = $this->get_columns($table);
+        if (empty($columns)) {
+            throw new dml_exception('ddltablenotexist', $table);
+        }
+
         $cleaned = array();
         $blobs   = array();
 
index cd87ef2..4301fe2 100644 (file)
@@ -29,5 +29,16 @@ defined('MOODLE_INTERNAL') || die();
 require_once(__DIR__.'/moodle_temptables.php');
 
 class pgsql_native_moodle_temptables extends moodle_temptables {
-    // I love these classes :-P
+    /**
+     * Analyze the data in temporary tables to force statistics collection after bulk data loads.
+     * PostgreSQL does not natively support automatic temporary table stats collection, so we do it.
+     *
+     * @return void
+     */
+    public function update_stats() {
+        $temptables = $this->get_temptables();
+        foreach ($temptables as $temptablename) {
+            $this->mdb->execute("ANALYZE {".$temptablename."}");
+        }
+    }
 }
index 093cda6..6f12524 100644 (file)
@@ -979,6 +979,10 @@ class sqlsrv_native_moodle_database extends moodle_database {
         $dataobject = (array)$dataobject;
 
         $columns = $this->get_columns($table);
+        if (empty($columns)) {
+            throw new dml_exception('ddltablenotexist', $table);
+        }
+
         $cleaned = array ();
 
         foreach ($dataobject as $field => $value) {
index d44714e..ceed3db 100644 (file)
@@ -2253,6 +2253,14 @@ class core_dml_testcase extends database_driver_testcase {
         } catch (moodle_exception $e) {
             $this->assertInstanceOf('dml_exception', $e);
         }
+
+        // Try to insert a record into a non-existent table. dml_exception expected.
+        try {
+            $DB->insert_record('nonexistenttable', $record, true);
+            $this->fail("Expecting an exception, none occurred");
+        } catch (exception $e) {
+            $this->assertTrue($e instanceof dml_exception);
+        }
     }
 
     public function test_import_record() {
index 7de1edb..4d54a14 100644 (file)
@@ -40,6 +40,15 @@ class tinymce_managefiles extends editor_tinymce_plugin {
             array $options = null) {
         global $USER;
 
+        if (!isloggedin() or isguestuser()) {
+            // Must be a real user to manage any files.
+            return;
+        }
+        if (!isset($options['maxfiles']) or $options['maxfiles'] == 0) {
+            // No files allowed - easy, do not load anything.
+            return;
+        }
+
         // Add parameters for filemanager
         $params['managefiles'] = array('usercontext' => context_user::instance($USER->id)->id);
         foreach (array('itemid', 'context', 'areamaxbytes', 'maxbytes', 'subdirs', 'return_types') as $key) {
index 1193086..2e62463 100644 (file)
@@ -109,7 +109,7 @@ class MoodleQuickForm_url extends HTML_QuickForm_text{
         if (count($options->repositories) > 0) {
             $straddlink = get_string('choosealink', 'repository');
             $str .= <<<EOD
-<button id="filepicker-button-{$client_id}" style="display:none">
+<button id="filepicker-button-{$client_id}" class="visibleifjs">
 $straddlink
 </button>
 EOD;
@@ -120,7 +120,6 @@ EOD;
 
         $module = array('name'=>'form_url', 'fullpath'=>'/lib/form/url.js', 'requires'=>array('core_filepicker'));
         $PAGE->requires->js_init_call('M.form_url.init', array($options), true, $module);
-        $PAGE->requires->js_function_call('show_item', array('filepicker-button-'.$client_id));
 
         return $str;
     }
index 190ab09..d5a9e6d 100644 (file)
@@ -967,10 +967,20 @@ class grade_category extends grade_object {
      *
      * @return bool True if extra credit used
      */
-    function is_extracredit_used() {
-        return ($this->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN2
-             or $this->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN
-             or $this->aggregation == GRADE_AGGREGATE_SUM);
+    public function is_extracredit_used() {
+        return self::aggregation_uses_extracredit($this->aggregation);
+    }
+
+    /**
+     * Returns true if aggregation passed is using extracredit.
+     *
+     * @param int $aggregation Aggregation const.
+     * @return bool True if extra credit used
+     */
+    public static function aggregation_uses_extracredit($aggregation) {
+        return ($aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN2
+             or $aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN
+             or $aggregation == GRADE_AGGREGATE_SUM);
     }
 
     /**
@@ -979,10 +989,21 @@ class grade_category extends grade_object {
      * @return bool True if an aggregation coefficient is being used
      */
     public function is_aggregationcoef_used() {
-        return ($this->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN
-             or $this->aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN2
-             or $this->aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN
-             or $this->aggregation == GRADE_AGGREGATE_SUM);
+        return self::aggregation_uses_aggregationcoef($this->aggregation);
+
+    }
+
+    /**
+     * Returns true if aggregation uses aggregationcoef
+     *
+     * @param int $aggregation Aggregation const.
+     * @return bool True if an aggregation coefficient is being used
+     */
+    public static function aggregation_uses_aggregationcoef($aggregation) {
+        return ($aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN
+             or $aggregation == GRADE_AGGREGATE_WEIGHTED_MEAN2
+             or $aggregation == GRADE_AGGREGATE_EXTRACREDIT_MEAN
+             or $aggregation == GRADE_AGGREGATE_SUM);
 
     }
 
@@ -1573,14 +1594,14 @@ class grade_category extends grade_object {
 
             //weight and extra credit share a column :( Would like a default of 1 for weight and 0 for extra credit
             //Flip from the default of 0 to 1 (or vice versa) if ALL items in the category are still set to the old default.
-            if ($params->aggregation==GRADE_AGGREGATE_WEIGHTED_MEAN || $params->aggregation==GRADE_AGGREGATE_EXTRACREDIT_MEAN) {
+            if (self::aggregation_uses_aggregationcoef($params->aggregation)) {
                 $sql = $defaultaggregationcoef = null;
 
-                if ($params->aggregation==GRADE_AGGREGATE_WEIGHTED_MEAN) {
+                if (!self::aggregation_uses_extracredit($params->aggregation)) {
                     //if all items in this category have aggregation coefficient of 0 we can change it to 1 ie evenly weighted
                     $sql = "select count(id) from {grade_items} where categoryid=:categoryid and aggregationcoef!=0";
                     $defaultaggregationcoef = 1;
-                } else if ($params->aggregation==GRADE_AGGREGATE_EXTRACREDIT_MEAN) {
+                } else {
                     //if all items in this category have aggregation coefficient of 1 we can change it to 0 ie no extra credit
                     $sql = "select count(id) from {grade_items} where categoryid=:categoryid and aggregationcoef!=1";
                     $defaultaggregationcoef = 0;
index d4ce639..5451609 100644 (file)
@@ -41,6 +41,7 @@ class core_grade_category_testcase extends grade_base_testcase {
         $this->sub_test_grade_category_aggregate_grades();
         $this->sub_test_grade_category_apply_limit_rules();
         $this->sub_test_grade_category_is_aggregationcoef_used();
+        $this->sub_test_grade_category_aggregation_uses_aggregationcoef();
         $this->sub_test_grade_category_fetch_course_tree();
         $this->sub_test_grade_category_get_children();
         $this->sub_test_grade_category_load_grade_item();
@@ -67,6 +68,8 @@ class core_grade_category_testcase extends grade_base_testcase {
 
         // Do this last as adding a second course category messes up the data.
         $this->sub_test_grade_category_insert_course_category();
+        $this->sub_test_grade_category_is_extracredit_used();
+        $this->sub_test_grade_category_aggregation_uses_extracredit();
     }
 
     // Adds 3 new grade categories at various depths.
@@ -531,11 +534,43 @@ class core_grade_category_testcase extends grade_base_testcase {
 
     }
 
-    /**
-     * TODO implement
-     */
     protected function sub_test_grade_category_is_aggregationcoef_used() {
+        $category = new grade_category();
+        // Following use aggregationcoef.
+        $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN;
+        $this->assertTrue($category->is_aggregationcoef_used());
+        $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2;
+        $this->assertTrue($category->is_aggregationcoef_used());
+        $category->aggregation = GRADE_AGGREGATE_EXTRACREDIT_MEAN;
+        $this->assertTrue($category->is_aggregationcoef_used());
+        $category->aggregation = GRADE_AGGREGATE_SUM;
+        $this->assertTrue($category->is_aggregationcoef_used());
 
+        // Following don't use aggregationcoef.
+        $category->aggregation = GRADE_AGGREGATE_MAX;
+        $this->assertFalse($category->is_aggregationcoef_used());
+        $category->aggregation = GRADE_AGGREGATE_MEAN;
+        $this->assertFalse($category->is_aggregationcoef_used());
+        $category->aggregation = GRADE_AGGREGATE_MEDIAN;
+        $this->assertFalse($category->is_aggregationcoef_used());
+        $category->aggregation = GRADE_AGGREGATE_MIN;
+        $this->assertFalse($category->is_aggregationcoef_used());
+        $category->aggregation = GRADE_AGGREGATE_MODE;
+        $this->assertFalse($category->is_aggregationcoef_used());
+    }
+
+    protected function sub_test_grade_category_aggregation_uses_aggregationcoef() {
+
+        $this->assertTrue(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_WEIGHTED_MEAN));
+        $this->assertTrue(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_WEIGHTED_MEAN2));
+        $this->assertTrue(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_EXTRACREDIT_MEAN));
+        $this->assertTrue(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_SUM));
+
+        $this->assertFalse(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_MAX));
+        $this->assertFalse(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_MEAN));
+        $this->assertFalse(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_MEDIAN));
+        $this->assertFalse(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_MIN));
+        $this->assertFalse(grade_category::aggregation_uses_aggregationcoef(GRADE_AGGREGATE_MODE));
     }
 
     protected function sub_test_grade_category_fetch_course_tree() {
@@ -721,4 +756,43 @@ class core_grade_category_testcase extends grade_base_testcase {
         $grade->insert();
         return $grade->rawgrade;
     }
+
+    protected function sub_test_grade_category_is_extracredit_used() {
+        $category = new grade_category();
+        // Following use aggregationcoef.
+        $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN2;
+        $this->assertTrue($category->is_extracredit_used());
+        $category->aggregation = GRADE_AGGREGATE_EXTRACREDIT_MEAN;
+        $this->assertTrue($category->is_extracredit_used());
+        $category->aggregation = GRADE_AGGREGATE_SUM;
+        $this->assertTrue($category->is_extracredit_used());
+
+        // Following don't use aggregationcoef.
+        $category->aggregation = GRADE_AGGREGATE_WEIGHTED_MEAN;
+        $this->assertFalse($category->is_extracredit_used());
+        $category->aggregation = GRADE_AGGREGATE_MAX;
+        $this->assertFalse($category->is_extracredit_used());
+        $category->aggregation = GRADE_AGGREGATE_MEAN;
+        $this->assertFalse($category->is_extracredit_used());
+        $category->aggregation = GRADE_AGGREGATE_MEDIAN;
+        $this->assertFalse($category->is_extracredit_used());
+        $category->aggregation = GRADE_AGGREGATE_MIN;
+        $this->assertFalse($category->is_extracredit_used());
+        $category->aggregation = GRADE_AGGREGATE_MODE;
+        $this->assertFalse($category->is_extracredit_used());
+    }
+
+    protected function sub_test_grade_category_aggregation_uses_extracredit() {
+
+        $this->assertTrue(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_WEIGHTED_MEAN2));
+        $this->assertTrue(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_EXTRACREDIT_MEAN));
+        $this->assertTrue(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_SUM));
+
+        $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_WEIGHTED_MEAN));
+        $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_MAX));
+        $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_MEAN));
+        $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_MEDIAN));
+        $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_MIN));
+        $this->assertFalse(grade_category::aggregation_uses_extracredit(GRADE_AGGREGATE_MODE));
+    }
 }
index df36acd..8fa85e9 100644 (file)
@@ -379,105 +379,6 @@ M.util.init_maximised_embed = function(Y, id) {
     };
 };
 
-/**
- * Attach handler to single_select
- *
- * This code was deprecated in Moodle 2.4 and will be removed in Moodle 2.6
- *
- * Please see lib/yui/formautosubmit/formautosubmit.js for its replacement
- */
-M.util.init_select_autosubmit = function(Y, formid, selectid, nothing) {
-    if (M.cfg.developerdebug) {
-        Y.log("You are using a deprecated function call (M.util.init_select_autosubmit). Please look at rewriting your call to use moodle-core-formautosubmit");
-    }
-    Y.use('event-key', function() {
-        var select = Y.one('#'+selectid);
-        if (select) {
-            // Try to get the form by id
-            var form = Y.one('#'+formid) || (function(){
-                // Hmmm the form's id may have been overriden by an internal input
-                // with the name id which will KILL IE.
-                // We need to manually iterate at this point because if the case
-                // above is true YUI's ancestor method will also kill IE!
-                var form = select;
-                while (form && form.get('nodeName').toUpperCase() !== 'FORM') {
-                    form = form.ancestor();
-                }
-                return form;
-            })();
-            // Make sure we have the form
-            if (form) {
-                var buttonflag = 0;
-                // Create a function to handle our change event
-                var processchange = function(e, paramobject) {
-                    if ((nothing===false || select.get('value') != nothing) && paramobject.lastindex != select.get('selectedIndex')) {
-                        // chrome doesn't pick up on a click when selecting an element in a select menu, so we use
-                        // the on change event to fire this function. This just checks to see if a button was
-                        // first pressed before redirecting to the appropriate page.
-                        if (Y.UA.os == 'windows' && Y.UA.chrome){
-                            if (buttonflag == 1) {
-                                buttonflag = 0;
-                                this.submit();
-                            }
-                        } else {
-                            this.submit();
-                        }
-                    }
-                    if (e.button == 1) {
-                        buttonflag = 1;
-                    }
-                    paramobject.lastindex = select.get('selectedIndex');
-                };
-
-                var changedown = function(e, paramobject) {
-                    if ((nothing===false || select.get('value') != nothing) && paramobject.lastindex != select.get('selectedIndex')) {
-                        if(e.keyCode == 13) {
-                            form.submit();
-                        }
-                        paramobject.lastindex = select.get('selectedIndex');
-                    }
-                }
-
-                var paramobject = new Object();
-                paramobject.lastindex = select.get('selectedIndex');
-                paramobject.eventchangeorblur = select.on('click', processchange, form, paramobject);
-                // Bad hack to circumvent problems with different browsers on different systems.
-                if (Y.UA.os == 'macintosh') {
-                    if(Y.UA.webkit) {
-                        paramobject.eventchangeorblur = select.on('change', processchange, form, paramobject);
-                    }
-                    paramobject.eventkeypress = Y.on('key', processchange, select, 'press:13', form, paramobject);
-                } else {
-                    if(Y.UA.os == 'windows' && Y.UA.chrome) {
-                        paramobject.eventchangeorblur = select.on('change', processchange, form, paramobject);
-                    }
-                    paramobject.eventkeypress = Y.on('keydown', changedown, select, '', form, paramobject);
-                }
-            }
-        }
-    });
-};
-
-/**
- * Attach handler to url_select
- * Deprecated from 2.4 onwards.
- * Please use @see init_select_autosubmit() for redirecting to a url (above).
- * This function has accessability issues and also does not use the formid passed through as a parameter.
- */
-M.util.init_url_select = function(Y, formid, selectid, nothing) {
-    if (M.cfg.developerdebug) {
-        Y.log("You are using a deprecated function call (M.util.init_url_select). Please look at rewriting your call to use moodle-core-formautosubmit");
-    }
-    YUI().use('node', function(Y) {
-        Y.on('change', function() {
-            if ((nothing == false && Y.Lang.isBoolean(nothing)) || Y.one('#'+selectid).get('value') != nothing) {
-                window.location = M.cfg.wwwroot+Y.one('#'+selectid).get('value');
-            }
-        },
-        '#'+selectid);
-    });
-};
-
 /**
  * Breaks out all links to the top frame - used in frametop page layout.
  */
@@ -1101,8 +1002,14 @@ function findParentNode(el, elName, elClass, elId) {
     specified tag name, class, and id. All conditions must be met,
     but any can be ommitted.
     Doesn't examine children of matches.
+
+    @deprecated since Moodle 2.7 - please do not use this function any more.
+    @todo MDL-43242 This will be deleted in Moodle 2.9.
+    @see Y.all
 */
 function findChildNodes(start, tagName, elementClass, elementID, elementName) {
+    Y.log("findChildNodes() is deprecated. Please use Y.all instead.",
+            "warn", "javascript-static.js");
     var children = new Array();
     for (var i = 0; i < start.childNodes.length; i++) {
         var classfound = false;
@@ -1252,8 +1159,11 @@ function insertAtCursor(myField, myValue) {
         Call instead of setting window.onload directly or setting body onload=.
         Adds your function to a chain of functions rather than overwriting anything
         that exists.
+        @deprecated Since Moodle 2.7. This will be removed in Moodle 2.9.
 */
 function addonload(fn) {
+    Y.log('addonload has been deprecated since Moodle 2.7 and will be removed in Moodle 2.9',
+            'warn', 'javascript-static.js');
     var oldhandler=window.onload;
     window.onload=function() {
         if(oldhandler) oldhandler();
@@ -1274,8 +1184,11 @@ function addonload(fn) {
  *                    document, use `document`.
  * @param {String} strTagName filter by tag names
  * @param {String} name same as HTML5 spec
+ * @deprecated Since Moodle 2.7. This will be removed in Moodle 2.9.
  */
 function getElementsByClassName(oElm, strTagName, name) {
+    Y.log('getElementsByClassName has been deprecated since Moodle 2.7 and will be removed in Moodle 2.9',
+            'warn', 'javascript-static.js');
     // for backwards compatibility
     if(typeof name == "object") {
         var names = new Array();
@@ -1447,19 +1360,24 @@ function close_window(e) {
 
 /**
  * Used in a couple of modules to hide navigation areas when using AJAX
+ * @deprecated since Moodle 2.7. This function will be removed in Moodle 2.9.
  */
-
 function show_item(itemid) {
-    var item = document.getElementById(itemid);
+    Y.log('show_item has been deprecated since Moodle 2.7 and will be removed in Moodle 2.9',
+            'warn', 'javascript-static.js');
+    var item = Y.one('#' + itemid);
     if (item) {
-        item.style.display = "";
+        item.show();
     }
 }
 
+// Deprecated since Moodle 2.7. This function will be removed in Moodle 2.9.
 function destroy_item(itemid) {
-    var item = document.getElementById(itemid);
+    Y.log('destroy_item has been deprecated since Moodle 2.7 and will be removed in Moodle 2.9',
+            'warn', 'javascript-static.js');
+    var item = Y.one('#' + itemid);
     if (item) {
-        item.parentNode.removeChild(item);
+        item.remove(true);
     }
 }
 /**
@@ -1552,12 +1470,14 @@ function update_progress_bar (id, width, pt, msg, es){
 
 /**
  * Used in a couple of modules to hide navigation areas when using AJAX
+ * @deprecated since Moodle 2.7. This function will be removed in Moodle 2.9.
  */
 function hide_item(itemid) {
-    // use class='hiddenifjs' instead
-    var item = document.getElementById(itemid);
+    Y.log('hide_item has been deprecated since Moodle 2.7 and will be removed in Moodle 2.9',
+            'warn', 'javascript-static.js');
+    var item = Y.one('#' + itemid);
     if (item) {
-        item.style.display = "none";
+        item.hide();
     }
 }
 
@@ -1597,30 +1517,6 @@ M.util.help_popups = {
     }
 }
 
-/**
- * This code bas been deprecated and will be removed from Moodle 2.7
- *
- * Please see lib/yui/popuphelp/popuphelp.js for its replacement
- */
-M.util.help_icon = {
-    initialised : false,
-    setup : function(Y, properties) {
-        this.add(Y, properties);
-    },
-    add : function(Y) {
-        if (M.cfg.developerdebug) {
-            Y.log("You are using a deprecated function call (M.util.help_icon.add). " +
-                    "Please look at rewriting your call to support lib/yui/popuphelp/popuphelp.js");
-        }
-        if (!this.initialised) {
-            YUI().use('moodle-core-popuphelp', function() {
-                M.core.init_popuphelp([]);
-            });
-        }
-        this.initialised = true;
-    }
-};
-
 /**
  * Custom menu namespace
  */
index e001185..9c136f3 100644 (file)
@@ -817,7 +817,7 @@ class core_media_player_qt extends core_media_player {
         <param name="pluginspage" value="http://www.apple.com/quicktime/download/" />
         <param name="src" value="$url" />
         <param name="controller" value="true" />
-        <param name="loop" value="true" />
+        <param name="loop" value="false" />
         <param name="autoplay" value="false" />
         <param name="autostart" value="false" />
         <param name="scale" value="aspect" />
@@ -826,7 +826,7 @@ class core_media_player_qt extends core_media_player {
             <param name="src" value="$url" />
             <param name="pluginurl" value="http://www.apple.com/quicktime/download/" />
             <param name="controller" value="true" />
-            <param name="loop" value="true" />
+            <param name="loop" value="false" />
             <param name="autoplay" value="false" />
             <param name="autostart" value="false" />
             <param name="scale" value="aspect" />
@@ -930,7 +930,7 @@ class core_media_player_swf extends core_media_player {
   <object classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" width="$width" height="$height">
     <param name="movie" value="$url" />
     <param name="autoplay" value="true" />
-    <param name="loop" value="true" />
+    <param name="loop" value="false" />
     <param name="controller" value="true" />
     <param name="scale" value="aspect" />
     <param name="base" value="." />
@@ -939,7 +939,7 @@ class core_media_player_swf extends core_media_player {
     <object type="application/x-shockwave-flash" data="$url" width="$width" height="$height">
       <param name="controller" value="true" />
       <param name="autoplay" value="true" />
-      <param name="loop" value="true" />
+      <param name="loop" value="false" />
       <param name="scale" value="aspect" />
       <param name="base" value="." />
       <param name="allowscriptaccess" value="never" />
index 6f53dcf..e69b3a4 100644 (file)
@@ -5696,6 +5696,11 @@ function email_to_user($user, $from, $subject, $messagetext, $messagehtml = '',
         return false;
     }
 
+    if (defined('BEHAT_SITE_RUNNING')) {
+        // Fake email sending in behat.
+        return true;
+    }
+
     if (!empty($CFG->noemailever)) {
         // Hidden setting for development sites, set in config.php if needed.
         debugging('Not sending email due to $CFG->noemailever config setting', DEBUG_NORMAL);
@@ -7650,7 +7655,6 @@ function random_string ($length=15) {
     $pool .= 'abcdefghijklmnopqrstuvwxyz';
     $pool .= '0123456789';
     $poollen = strlen($pool);
-    mt_srand ((double) microtime() * 1000000);
     $string = '';
     for ($i = 0; $i < $length; $i++) {
         $string .= substr($pool, (mt_rand()%($poollen)), 1);
@@ -7671,7 +7675,6 @@ function complex_random_string($length=null) {
     $pool  = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
     $pool .= '`~!@#%^&*()_+-=[];,./<>?:{} ';
     $poollen = strlen($pool);
-    mt_srand ((double) microtime() * 1000000);
     if ($length===null) {
         $length = floor(rand(24, 32));
     }
@@ -7971,7 +7974,6 @@ function unformat_float($localefloat, $strict = false) {
  */
 function swapshuffle($array) {
 
-    srand ((double) microtime() * 10000000);
     $last = count($array) - 1;
     for ($i = 0; $i <= $last; $i++) {
         $from = rand(0, $last);
@@ -8011,7 +8013,6 @@ function swapshuffle_assoc($array) {
  * @return array
  */
 function draw_rand_array($array, $draws) {
-    srand ((double) microtime() * 10000000);
 
     $return = array();
 
index 24a3f56..f1470f9 100644 (file)
@@ -226,6 +226,20 @@ class page_requirements_manager {
             )
         ));
 
+        $this->YUI_config->add_group('gallery', array(
+            'name' => 'gallery',
+            'base' => $CFG->httpswwwroot . '/lib/yuilib/gallery/',
+            'combine' => $this->yui3loader->combine,
+            'comboBase' => $CFG->httpswwwroot . '/theme/yui_combo.php' . $sep,
+            'ext' => false,
+            'root' => 'gallery/' . $jsrev . '/',
+            'patterns' => array(
+                'gallery-' => array(
+                    'group' => 'gallery',
+                )
+            )
+        ));
+
         // Set some more loader options applying to groups too.
         if ($CFG->debugdeveloper) {
             // When debugging is enabled, we want to load the non-minified (RAW) versions of YUI library modules rather
@@ -240,6 +254,7 @@ class page_requirements_manager {
             $this->YUI_config->debug = true;
         } else {
             $this->yui3loader->filter = null;
+            $this->YUI_config->groups['moodle']['filter'] = null;
             $this->YUI_config->debug = false;
         }
 
@@ -287,6 +302,9 @@ class page_requirements_manager {
         if ($CFG->debugdeveloper) {
             $this->M_cfg['developerdebug'] = true;
         }
+        if (defined('BEHAT_SITE_RUNNING')) {
+            $this->M_cfg['behatsiterunning'] = true;
+        }
 
         // Accessibility stuff.
         $this->skip_link_to('maincontent', get_string('tocontent', 'access'));
@@ -979,27 +997,19 @@ class page_requirements_manager {
      * @param array|string $modules One or more modules
      * @param string $function The function to call once modules have been loaded
      * @param array $arguments An array of arguments to pass to the function
-     * @param string $galleryversion The gallery version to use
+     * @param string $galleryversion Deprecated: The gallery version to use
      * @param bool $ondomready
      */
     public function yui_module($modules, $function, array $arguments = null, $galleryversion = null, $ondomready = false) {
-        global $CFG;
-
-        if (!$galleryversion) {
-            $galleryversion = '2010.04.08-12-35';
-        }
-
         if (!is_array($modules)) {
             $modules = array($modules);
         }
-        if (empty($CFG->useexternalyui)) {
-            // We need to set the M.yui.galleryversion to the correct version
-            $jscode = 'M.yui.galleryversion='.json_encode($galleryversion).';';
-        } else {
-            // Set Y's config.gallery to the version
-            $jscode = 'Y.config.gallery='.json_encode($galleryversion).';';
+
+        if ($galleryversion != null) {
+            debugging('The galleryversion parameter to yui_module has been deprecated since Moodle 2.3.');
         }
-        $jscode .= 'Y.use('.join(',', array_map('json_encode', convert_to_array($modules))).',function() {'.js_writer::function_call($function, $arguments).'});';
+
+        $jscode = 'Y.use('.join(',', array_map('json_encode', convert_to_array($modules))).',function() {'.js_writer::function_call($function, $arguments).'});';
         if ($ondomready) {
             $jscode = "Y.on('domready', function() { $jscode });";
         }
index 9df959f..f1d3054 100644 (file)
@@ -59,95 +59,60 @@ if (!isset($CFG)) {
 // it can not be anything else, there is no point in having this in config.php
 $CFG->dirroot = dirname(dirname(__FILE__));
 
-// Normalise dataroot - we do not want any symbolic links, trailing / or any other weirdness there
-if (!isset($CFG->dataroot)) {
-    if (isset($_SERVER['REMOTE_ADDR'])) {
-        header($_SERVER['SERVER_PROTOCOL'] . ' 503 Service Unavailable');
-    }
-    echo('Fatal error: $CFG->dataroot is not specified in config.php! Exiting.'."\n");
-    exit(1);
+// File permissions on created directories in the $CFG->dataroot
+if (!isset($CFG->directorypermissions)) {
+    $CFG->directorypermissions = 02777;      // Must be octal (that's why it's here)
 }
-$CFG->dataroot = realpath($CFG->dataroot);
-if ($CFG->dataroot === false) {
-    if (isset($_SERVER['REMOTE_ADDR'])) {
-        header($_SERVER['SERVER_PROTOCOL'] . ' 503 Service Unavailable');
-    }
-    echo('Fatal error: $CFG->dataroot is not configured properly, directory does not exist or is not accessible! Exiting.'."\n");
-    exit(1);
-} else if (!is_writable($CFG->dataroot)) {
-    if (isset($_SERVER['REMOTE_ADDR'])) {
-        header($_SERVER['SERVER_PROTOCOL'] . ' 503 Service Unavailable');
-    }
-    echo('Fatal error: $CFG->dataroot is not writable, admin has to fix directory permissions! Exiting.'."\n");
-    exit(1);
+if (!isset($CFG->filepermissions)) {
+    $CFG->filepermissions = ($CFG->directorypermissions & 0666); // strip execute flags
 }
-
-// wwwroot is mandatory
-if (!isset($CFG->wwwroot) or $CFG->wwwroot === 'http://example.com/moodle') {
-    if (isset($_SERVER['REMOTE_ADDR'])) {
-        header($_SERVER['SERVER_PROTOCOL'] . ' 503 Service Unavailable');
-    }
-    echo('Fatal error: $CFG->wwwroot is not configured! Exiting.'."\n");
-    exit(1);
+// Better also set default umask because developers often forget to include directory
+// permissions in mkdir() and chmod() after creating new files.
+if (!isset($CFG->umaskpermissions)) {
+    $CFG->umaskpermissions = (($CFG->directorypermissions & 0777) ^ 0777);
 }
+umask($CFG->umaskpermissions);
 
-// Test environment is requested if:
-// * If $CFG->behat_switchcompletely has been set (maintains CLI scripts behaviour, which ATM is only preventive).
-// * If we are accessing though the built-in web server (cli-server).
-// * Behat is running (constant set hooking the behat init process before requiring config.php).
-// * If $CFG->behat_wwwroot has been set and the hostname/port match what the page was requested with.
-// Test environment is enabled if:
-// * User has previously enabled through admin/tool/behat/cli/util.php --enable or admin/tool/behat/cli/init.php
-// Both are required to switch to test mode
-if (!defined('BEHAT_SITE_RUNNING') && !empty($CFG->behat_dataroot) &&
-        !empty($CFG->behat_prefix) && file_exists($CFG->behat_dataroot)) {
+if (defined('BEHAT_SITE_RUNNING')) {
+    // We already switched to behat test site previously.
 
-    // Only included if behat_* are set, it is not likely to be a production site.
+} else if (!empty($CFG->behat_wwwroot) or !empty($CFG->behat_dataroot) or !empty($CFG->behat_prefix)) {
+    // The behat is configured on this server, we need to find out if this is the behat test
+    // site based on the URL used for access.
     require_once(__DIR__ . '/../lib/behat/lib.php');
+    if (behat_is_test_site()) {
+        // Checking the integrity of the provided $CFG->behat_* vars and the
+        // selected wwwroot to prevent conflicts with production and phpunit environments.
+        behat_check_config_vars();
 
-    $defaultbehatwwwroot = behat_get_wwwroot();
-
-    if (!empty($CFG->behat_switchcompletely) && php_sapi_name() !== 'cli') {
-        // Switch completely uses the production wwwroot as the test site URL.
-        $behatwwwroot = $defaultbehatwwwroot;
+        // Check that the directory does not contains other things.
+        if (!file_exists("$CFG->behat_dataroot/behattestdir.txt")) {
+            if ($dh = opendir($CFG->behat_dataroot)) {
+                while (($file = readdir($dh)) !== false) {
+                    if ($file === 'behat' or $file === '.' or $file === '..' or $file === '.DS_Store') {
+                        continue;
+                    }
+                    behat_error(BEHAT_EXITCODE_CONFIG, '$CFG->behat_dataroot directory is not empty, ensure this is the directory where you want to install behat test dataroot');
+                }
+                closedir($dh);
+                unset($dh);
+                unset($file);
+            }
 
-    } elseif (php_sapi_name() === 'cli-server') {
-        // If we are using the built-in server we use the provided $CFG->behat_wwwroot
-        // value or the default one if $CFG->behat_wwwroot is not set, only if it matches
-        // the requested URL.
-        if (behat_is_requested_url($defaultbehatwwwroot)) {
-            $behatwwwroot = $defaultbehatwwwroot;
+            if (defined('BEHAT_UTIL')) {
+                // Now we create dataroot directory structure for behat tests.
+                testing_initdataroot($CFG->behat_dataroot, 'behat');
+            } else {
+                behat_error(BEHAT_EXITCODE_INSTALL);
+            }
         }
 
-    } elseif (defined('BEHAT_TEST')) {
-        // This is when moodle codebase runs through vendor/bin/behat, we "are not supposed"
-        // to need a wwwroot, but before using the production one we should set something else
-        // as an alternative.
-        $behatwwwroot = $defaultbehatwwwroot;
-
-    } elseif (!empty($CFG->behat_wwwroot) && !empty($_SERVER['HTTP_HOST'])) {
-        // If $CFG->behat_wwwroot was set and matches the requested URL we
-        // use $CFG->behat_wwwroot as our wwwroot.
-        if (behat_is_requested_url($CFG->behat_wwwroot)) {
-            $behatwwwroot = $CFG->behat_wwwroot;
+        if (!defined('BEHAT_UTIL') and !defined('BEHAT_TEST')) {
+            // Somebody tries to access test site directly, tell them if not enabled.
+            if (!file_exists($CFG->behat_dataroot . '/behat/test_environment_enabled.txt')) {
+                behat_error(BEHAT_EXITCODE_CONFIG, 'Behat is configured but not enabled on this test site.');
+            }
         }
-    }
-
-    // If we found a proper behatwwwroot then we consider the behat test as requested.
-    $testenvironmentrequested = !empty($behatwwwroot);
-
-    // Only switch to test environment if it has been enabled.
-    $CFG->behat_dataroot = realpath($CFG->behat_dataroot);
-    $testenvironmentenabled = file_exists($CFG->behat_dataroot . '/behat/test_environment_enabled.txt');
-
-    if ($testenvironmentenabled && $testenvironmentrequested) {
-
-        // Now we know which one will be our behat wwwroot.
-        $CFG->behat_wwwroot = $behatwwwroot;
-
-        // Checking the integrity of the provided $CFG->behat_* vars and the
-        // selected wwwroot to prevent conflicts with production and phpunit environments.
-        behat_check_config_vars();
 
         // Constant used to inform that the behat test site is being used,
         // this includes all the processes executed by the behat CLI command like
@@ -169,6 +134,38 @@ if (!defined('BEHAT_SITE_RUNNING') && !empty($CFG->behat_dataroot) &&
     }
 }
 
+// Normalise dataroot - we do not want any symbolic links, trailing / or any other weirdness there
+if (!isset($CFG->dataroot)) {
+    if (isset($_SERVER['REMOTE_ADDR'])) {
+        header($_SERVER['SERVER_PROTOCOL'] . ' 503 Service Unavailable');
+    }
+    echo('Fatal error: $CFG->dataroot is not specified in config.php! Exiting.'."\n");
+    exit(1);
+}
+$CFG->dataroot = realpath($CFG->dataroot);
+if ($CFG->dataroot === false) {
+    if (isset($_SERVER['REMOTE_ADDR'])) {
+        header($_SERVER['SERVER_PROTOCOL'] . ' 503 Service Unavailable');
+    }
+    echo('Fatal error: $CFG->dataroot is not configured properly, directory does not exist or is not accessible! Exiting.'."\n");
+    exit(1);
+} else if (!is_writable($CFG->dataroot)) {
+    if (isset($_SERVER['REMOTE_ADDR'])) {
+        header($_SERVER['SERVER_PROTOCOL'] . ' 503 Service Unavailable');
+    }
+    echo('Fatal error: $CFG->dataroot is not writable, admin has to fix directory permissions! Exiting.'."\n");
+    exit(1);
+}
+
+// wwwroot is mandatory
+if (!isset($CFG->wwwroot) or $CFG->wwwroot === 'http://example.com/moodle') {
+    if (isset($_SERVER['REMOTE_ADDR'])) {
+        header($_SERVER['SERVER_PROTOCOL'] . ' 503 Service Unavailable');
+    }
+    echo('Fatal error: $CFG->wwwroot is not configured! Exiting.'."\n");
+    exit(1);
+}
+
 // Make sure there is some database table prefix.
 if (!isset($CFG->prefix)) {
     $CFG->prefix = '';
@@ -219,6 +216,7 @@ if (!isset($_SERVER['REMOTE_ADDR']) && isset($_SERVER['argv'][0])) {
 
 // sometimes default PHP settings are borked on shared hosting servers, I wonder why they have to do that??
 ini_set('precision', 14); // needed for upgrades and gradebook
+ini_set('serialize_precision', 17); // Make float serialization consistent on all systems.
 
 // Scripts may request no debug and error messages in output
 // please note it must be defined before including the config.php script
@@ -334,10 +332,10 @@ if (file_exists("$CFG->dataroot/climaintenance.html")) {
 
 if (CLI_SCRIPT) {
     // sometimes people use different PHP binary for web and CLI, make 100% sure they have the supported PHP version
-    if (version_compare(phpversion(), '5.3.3') < 0) {
+    if (version_compare(phpversion(), '5.4.4') < 0) {
         $phpversion = phpversion();
         // do NOT localise - lang strings would not work here and we CAN NOT move it to later place
-        echo "Moodle 2.5 or later requires at least PHP 5.3.3 (currently using version $phpversion).\n";
+        echo "Moodle 2.7 or later requires at least PHP 5.4.4 (currently using version $phpversion).\n";
         echo "Some servers may have multiple PHP versions installed, are you using the correct executable?\n";
         exit(1);
     }
@@ -348,20 +346,6 @@ if (!defined('AJAX_SCRIPT')) {
     define('AJAX_SCRIPT', false);
 }
 
-// File permissions on created directories in the $CFG->dataroot
-if (!isset($CFG->directorypermissions)) {
-    $CFG->directorypermissions = 02777;      // Must be octal (that's why it's here)
-}
-if (!isset($CFG->filepermissions)) {
-    $CFG->filepermissions = ($CFG->directorypermissions & 0666); // strip execute flags
-}
-// Better also set default umask because developers often forget to include directory
-// permissions in mkdir() and chmod() after creating new files.
-if (!isset($CFG->umaskpermissions)) {
-    $CFG->umaskpermissions = (($CFG->directorypermissions & 0777) ^ 0777);
-}
-umask($CFG->umaskpermissions);
-
 // Exact version of currently used yui2 and 3 library.
 $CFG->yui2version = '2.9.0';
 $CFG->yui3version = '3.13.0';
index 84e9a5a..1c918b4 100644 (file)
@@ -259,6 +259,7 @@ function stats_cron_daily($maxdays=1) {
             $failed = true;
             break;
         }
+        $DB->update_temp_table_stats();
 
         stats_progress('1');
 
@@ -385,6 +386,10 @@ function stats_cron_daily($maxdays=1) {
             $failed = true;
             break;
         }
+        // The steps up until this point, all add to {temp_stats_daily} and don't use new tables.
+        // There is no point updating statistics as they won't be used until the DELETE below.
+        $DB->update_temp_table_stats();
+
         stats_progress('7');
 
         // Default frontpage role enrolments are all site users (not deleted)
@@ -581,6 +586,7 @@ function stats_cron_daily($maxdays=1) {
             $failed = true;
             break;
         }
+        $DB->update_temp_table_stats();
         stats_progress('15');
 
         // How many view actions for guests or not-logged-in on frontpage
@@ -1736,6 +1742,9 @@ function stats_temp_table_fill($timestart, $timeend) {
 
     $DB->execute($sql);
 
+    // We have just loaded all the temp tables, collect statistics for that.
+    $DB->update_temp_table_stats();
+
     return true;
 }
 
index 41a4243..661481f 100644 (file)
@@ -644,18 +644,23 @@ abstract class testing_util {
             return null;
         }
 
-        $ref = file_get_contents("$CFG->dirroot/.git/HEAD");
-        if ($ref === false) {
+        $headcontent = file_get_contents("$CFG->dirroot/.git/HEAD");
+        if ($headcontent === false) {
             return null;
         }
 
-        $ref = trim($ref);
+        $headcontent = trim($headcontent);
 
-        if (strpos($ref, 'ref: ') !== 0) {
+        // If it is pointing to a hash we return it directly.
+        if (strlen($headcontent) === 40) {
+            return $headcontent;
+        }
+
+        if (strpos($headcontent, 'ref: ') !== 0) {
             return null;
         }
 
-        $ref = substr($ref, 5);
+        $ref = substr($headcontent, 5);
 
         if (!file_exists("$CFG->dirroot/.git/$ref")) {
             return null;
index 4cee9b1..c67a1a9 100644 (file)
@@ -38,7 +38,13 @@ function testing_cli_argument_path($moodlepath) {
         $moodlepath = preg_replace('|^/admin/|', "/$CFG->admin/", $moodlepath);
     }
 
-    $cwd = getcwd();
+    if (isset($_SERVER['REMOTE_ADDR'])) {
+        // Web access, this should not happen often.
+        $cwd = dirname(dirname(__DIR__));
+    } else {
+        // This is the real CLI script, work with relative paths.
+        $cwd = getcwd();
+    }
     if (substr($cwd, -1) !== DIRECTORY_SEPARATOR) {
         $cwd .= DIRECTORY_SEPARATOR;
     }
index b1cba20..80df165 100644 (file)
@@ -2274,8 +2274,6 @@ class core_accesslib_testcase extends advanced_testcase {
             $userids = array_slice($userids, 0, 5);
         }
 
-        // Random time!
-        // srand(666);
         foreach ($userids as $userid) { // No guest or deleted.
             // Each user gets 0-10 random roles.
             $rcount = rand(0, 10);
diff --git a/lib/tests/ajaxlib_test.php b/lib/tests/ajaxlib_test.php
new file mode 100644 (file)
index 0000000..9e80697
--- /dev/null
@@ -0,0 +1,113 @@
+<?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/>.
+
+/**
+ * Code quality unit tests that are fast enough to run each time.
+ *
+ * @package    core
+ * @category   phpunit
+ * @copyright  2013 Andrew Nicols
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU Public License
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+class core_ajaxlib_testcase extends advanced_testcase {
+
+    protected function helper_test_clean_output() {
+        $this->resetAfterTest();
+
+        $result = ajax_capture_output();
+
+        // ob_start should normally return without issue.
+        $this->assertTrue($result);
+
+        $result = ajax_check_captured_output();
+        $this->assertEmpty($result);
+    }
+
+    protected function helper_test_dirty_output($expectexception = false) {
+        $this->resetAfterTest();
+
+        // Keep track of the content we will output.
+        $content = "Some example content";
+
+        $result = ajax_capture_output();
+
+        // ob_start should normally return without issue.
+        $this->assertTrue($result);
+
+        // Fill the output buffer.
+        echo $content;
+
+        if ($expectexception) {
+            $this->setExpectedException('coding_exception');
+            ajax_check_captured_output();
+        } else {
+            $result = ajax_check_captured_output();
+            $this->assertEquals($result, $content);
+        }
+    }
+
+    public function test_output_capture_normal_debug_none() {
+        // In normal conditions, and with DEBUG_NONE set, we should not receive any output or throw any exceptions.
+        set_debugging(DEBUG_NONE);
+        $this->helper_test_clean_output();
+    }
+
+    public function test_output_capture_normal_debug_normal() {
+        // In normal conditions, and with DEBUG_NORMAL set, we should not receive any output or throw any exceptions.
+        set_debugging(DEBUG_NORMAL);
+        $this->helper_test_clean_output();
+    }
+
+    public function test_output_capture_normal_debug_all() {
+        // In normal conditions, and with DEBUG_ALL set, we should not receive any output or throw any exceptions.
+        set_debugging(DEBUG_ALL);
+        $this->helper_test_clean_output();
+    }
+
+    public function test_output_capture_normal_debugdeveloper() {
+        // In normal conditions, and with DEBUG_DEVELOPER set, we should not receive any output or throw any exceptions.
+        set_debugging(DEBUG_DEVELOPER);
+        $this->helper_test_clean_output();
+    }
+
+    public function test_output_capture_error_debug_none() {
+        // With DEBUG_NONE set, we should not throw any exception, but the output will be returned.
+        set_debugging(DEBUG_NONE);
+        $this->helper_test_dirty_output();
+    }
+
+    public function test_output_capture_error_debug_normal() {
+        // With DEBUG_NORMAL set, we should not throw any exception, but the output will be returned.
+        set_debugging(DEBUG_NORMAL);
+        $this->helper_test_dirty_output();
+    }
+
+    public function test_output_capture_error_debug_all() {
+        // In error conditions, and with DEBUG_ALL set, we should not receive any output or throw any exceptions.
+        set_debugging(DEBUG_ALL);
+        $this->helper_test_dirty_output();
+    }
+
+    public function test_output_capture_error_debugdeveloper() {
+        // With DEBUG_DEVELOPER set, we should throw an exception.
+        set_debugging(DEBUG_DEVELOPER);
+        $this->helper_test_dirty_output(true);
+    }
+
+}
index 81285c0..b521638 100644 (file)
@@ -67,6 +67,16 @@ class behat_hooks extends behat_base {
      */
     protected static $initprocessesfinished = false;
 
+    /**
+     * Some exceptions can only be caught in a before or after step hook,
+     * they can not be thrown there as they will provoke a framework level
+     * failure, but we can store them here to fail the step in i_look_for_exceptions()
+     * which result will be parsed by the framework as the last step result.
+     *
+     * @var Null or the exception last step throw in the before or after hook.
+     */
+    protected static $currentstepexception = null;
+
     /**
      * Gives access to moodle codebase, ensures all is ready and sets up the test lock.
      *
@@ -107,7 +117,7 @@ class behat_hooks extends behat_base {
 
         if (!behat_util::is_server_running()) {
             throw new Exception($CFG->behat_wwwroot .
-                ' is not available, ensure you started your PHP built-in server or your web server is correctly started and set up.' .
+                ' is not available, ensure you specified correct url and that the server is set up and started.' .
                 ' More info in ' . behat_command::DOCS_URL . '#Running_tests');
         }
 
@@ -210,26 +220,27 @@ class behat_hooks extends behat_base {
             self::$initprocessesfinished = true;
         }
 
-        // Closing JS dialogs if present. Otherwise they would block this scenario execution.
-        if ($this->running_javascript()) {
-            try {
-                $session->getDriver()->getWebDriverSession()->accept_alert();
-            } catch (NoAlertOpenError $e) {
-                // All ok, there should not be JS dialogs in theory.
-            }
-        }
-
     }
 
     /**
      * Wait for JS to complete before beginning interacting with the DOM.
      *
-     * Executed only when running against a real browser.
+     * Executed only when running against a real browser. We wrap it
+     * all in a try & catch to forward the exception to i_look_for_exceptions
+     * so the exception will be at scenario level, which causes a failure, by
+     * default would be at framework level, which will stop the execution of
+     * the run.
      *
      * @BeforeStep @javascript
      */
     public function before_step_javascript($event) {
-        $this->wait_for_pending_js();
+
+        try {
+            $this->wait_for_pending_js();
+            self::$currentstepexception = null;
+        } catch (Exception $e) {
+            self::$currentstepexception = $e;
+        }
     }
 
     /**
@@ -238,12 +249,33 @@ class behat_hooks extends behat_base {
      * With this we ensure that there are not AJAX calls
      * still in progress.
      *
-     * Executed only when running against a real browser.
+     * Executed only when running against a real browser. We wrap it
+     * all in a try & catch to forward the exception to i_look_for_exceptions
+     * so the exception will be at scenario level, which causes a failure, by
+     * default would be at framework level, which will stop the execution of
+     * the run.
      *
      * @AfterStep @javascript
      */
     public function after_step_javascript($event) {
-        $this->wait_for_pending_js();
+
+        try {
+            $this->wait_for_pending_js();
+            self::$currentstepexception = null;
+        } catch (UnexpectedAlertOpen $e) {
+            self::$currentstepexception = $e;
+
+            // Accepting the alert so the framework can continue properly running
+            // the following scenarios. Some browsers already closes the alert, so
+            // wrapping in a try & catch.
+            try {
+                $this->getSession()->getDriver()->getWebDriverSession()->accept_alert();
+            } catch (Exception $e) {
+                // Catching the generic one as we never know how drivers reacts here.
+            }
+        } catch (Exception $e) {
+            self::$currentstepexception = $e;
+        }
     }
 
     /**
@@ -267,9 +299,10 @@ class behat_hooks extends behat_base {
                 // No javascript is running if there is no window right?
                 $pending = '';
             } catch (UnknownError $e) {
-                // Same exception as before, but some combinations of browser + OS reports it as an unknown error
-                // exception.
-                $pending = '';
+                // M is not defined when the window or the frame don't exist anymore.
+                if (strstr($e->getMessage(), 'M is not defined') != false) {
+                    $pending = '';
+                }
             }
 
             // If there are no pending JS we stop waiting.
@@ -293,10 +326,16 @@ class behat_hooks extends behat_base {
      * after each step so no features will splicitly use it.
      *
      * @Given /^I look for exceptions$/
+     * @throw Exception Unknown type, depending on what we caught in the hook or basic \Exception.
      * @see Moodle\BehatExtension\Tester\MoodleStepTester
      */
     public function i_look_for_exceptions() {
 
+        // If the step already failed in a hook throw the exception.
+        if (!is_null(self::$currentstepexception)) {
+            throw self::$currentstepexception;
+        }
+
         // Wrap in try in case we were interacting with a closed window.
         try {
 
@@ -368,13 +407,6 @@ class behat_hooks extends behat_base {
 
         } catch (NoSuchWindow $e) {
             // If we were interacting with a popup window it will not exists after closing it.
-        } catch (UnexpectedAlertOpen $e) {
-            // We fail the scenario if we find an opened JS alert/confirm, in most of the cases it
-            // will be there because we are leaving an edited form without submitting/cancelling
-            // it, but moodle is using JS confirms and we can not just cancel the JS dialog
-            // as in some cases (delete activity with JS enabled for example) the test writer should
-            // use extra steps to deal with moodle's behaviour.
-            throw new Exception('Modal window present. Ensure there are no edited forms pending to submit/cancel.');
         }
     }
 
diff --git