Merge branch 'MDL-56755-m' of https://github.com/micaherne/moodle
authorAndrew Nicols <andrew@nicols.co.uk>
Wed, 9 Nov 2016 07:42:32 +0000 (15:42 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Wed, 9 Nov 2016 07:42:32 +0000 (15:42 +0800)
530 files changed:
.eslintignore
.stylelintignore
admin/media.php [new file with mode: 0644]
admin/message.php
admin/mnet/peer_forms.php
admin/mnet/peers.php
admin/mnet/profilefields.php
admin/mnet/services.php
admin/roles/ajax.php
admin/roles/classes/permissions_table.php
admin/search.php
admin/settings/appearance.php
admin/settings/plugins.php
admin/settings/security.php
admin/settings/server.php
admin/settings/top.php
admin/templates/settings_search_results.mustache
admin/tool/behat/tests/behat/get_and_set_fields.feature
admin/tool/langimport/classes/controller.php
admin/tool/lp/amd/build/menubar.min.js
admin/tool/lp/amd/src/menubar.js
admin/tool/lp/lib.php
admin/tool/lp/styles.css
admin/tool/lp/templates/action_selector.mustache
admin/tool/lp/templates/comment_area.mustache
admin/tool/lp/templates/competencies_move_tree.mustache
admin/tool/lp/templates/competencies_tree.mustache
admin/tool/lp/templates/competencies_tree_root.mustache
admin/tool/lp/templates/competency_grader.mustache
admin/tool/lp/templates/competency_path.mustache
admin/tool/lp/templates/competency_picker.mustache
admin/tool/lp/templates/competency_picker_competencyform.mustache
admin/tool/lp/templates/competency_picker_user_plans.mustache
admin/tool/lp/templates/competency_plan_navigation.mustache
admin/tool/lp/templates/competency_rule_config.mustache
admin/tool/lp/templates/competency_rule_points.mustache
admin/tool/lp/templates/competency_summary.mustache
admin/tool/lp/templates/course_competencies_page.mustache
admin/tool/lp/templates/course_competency_settings.mustache
admin/tool/lp/templates/course_competency_statistics.mustache
admin/tool/lp/templates/evidence_summary.mustache
admin/tool/lp/templates/linked_courses_summary.mustache
admin/tool/lp/templates/manage_competencies_page.mustache
admin/tool/lp/templates/manage_competency_frameworks_page.mustache
admin/tool/lp/templates/manage_templates_page.mustache
admin/tool/lp/templates/no_frameworks_warning.mustache
admin/tool/lp/templates/plan_page.mustache
admin/tool/lp/templates/plans_page.mustache
admin/tool/lp/templates/related_competencies.mustache
admin/tool/lp/templates/scale_configuration_page.mustache
admin/tool/lp/templates/template_competencies_page.mustache
admin/tool/lp/templates/template_statistics.mustache
admin/tool/lp/templates/user_competency_course_navigation.mustache
admin/tool/lp/templates/user_competency_summary.mustache
admin/tool/lp/templates/user_competency_summary_in_course.mustache
admin/tool/lp/templates/user_competency_summary_in_plan.mustache
admin/tool/lp/templates/user_evidence_list_page.mustache
admin/tool/lp/templates/user_evidence_page.mustache
admin/tool/lp/tests/behat/behat_tool_lp.php
admin/tool/lpmigrate/frameworks.php
admin/tool/messageinbound/classes/manager.php
admin/tool/messageinbound/settings.php
admin/tool/mobile/lang/en/tool_mobile.php
admin/tool/mobile/launch.php
admin/tool/mobile/settings.php
admin/tool/mobile/tests/externallib_test.php
admin/tool/monitor/index.php
admin/tool/recyclebin/lib.php
admin/tool/recyclebin/tests/behat/backup_user_data.feature
admin/tool/recyclebin/tests/behat/basic_functionality.feature
admin/tool/recyclebin/tests/course_bin_test.php
admin/tool/templatelibrary/amd/build/display.min.js
admin/tool/templatelibrary/amd/build/search.min.js
admin/tool/templatelibrary/amd/src/display.js
admin/tool/templatelibrary/amd/src/search.js
admin/tool/templatelibrary/classes/api.php
admin/tool/templatelibrary/classes/external.php
admin/tool/usertours/amd/build/popper.min.js
admin/tool/usertours/amd/build/tour.min.js
admin/tool/usertours/amd/src/popper.js
admin/tool/usertours/amd/src/tour.js
admin/tool/usertours/classes/manager.php
admin/tool/usertours/thirdpartylibs.xml
auth/email/classes/external.php
auth/radius/auth.php [deleted file]
auth/radius/config.html [deleted file]
auth/radius/db/install.php [deleted file]
auth/radius/lang/en/auth_radius.php [deleted file]
auth/upgrade.txt
availability/classes/tree_node.php
availability/condition/completion/classes/frontend.php
availability/condition/grade/classes/frontend.php
availability/condition/grade/tests/behat/availability_grade.feature
availability/tests/tree_test.php
backup/util/dbops/backup_plan_dbops.class.php
backup/util/loggers/base_logger.class.php
badges/tests/badgeslib_test.php
blocks/recent_activity/tests/behat/structural_changes.feature
blog/index.php
blog/rsslib.php
cache/classes/dummystore.php
cache/classes/factory.php
cache/stores/apcu/lib.php
cache/stores/file/lib.php
cache/stores/memcache/lib.php
cache/stores/memcache/tests/memcache_test.php
cache/stores/memcached/lib.php
cache/stores/memcached/tests/memcached_test.php
cache/stores/mongodb/tests/mongodb_test.php
cache/stores/redis/README.md [new file with mode: 0644]
cache/stores/redis/addinstanceform.php [new file with mode: 0644]
cache/stores/redis/lang/en/cachestore_redis.php [new file with mode: 0644]
cache/stores/redis/lib.php [new file with mode: 0644]
cache/stores/redis/settings.php [new file with mode: 0644]
cache/stores/redis/tests/redis_test.php [new file with mode: 0644]
cache/stores/redis/version.php [new file with mode: 0644]
cache/tests/fixtures/stores.php
calendar/lib.php
calendar/tests/lib_test.php
cohort/index.php
competency/classes/user_competency_plan.php
completion/tests/behat/restrict_activity_by_grade.feature
completion/tests/behat/restrict_section_availability.feature
course/classes/task/course_delete_modules.php [new file with mode: 0644]
course/editsection.php
course/lib.php
course/rest.php
course/tests/behat/activities_edit_completion.feature
course/tests/courselib_test.php
enrol/lti/classes/data_connector.php
enrol/lti/classes/manage_table.php
enrol/lti/classes/task/sync_members.php
enrol/lti/classes/tool_provider.php
enrol/lti/db/install.xml
enrol/lti/db/upgrade.php
enrol/lti/index.php
enrol/lti/lang/en/deprecated.txt [new file with mode: 0644]
enrol/lti/lang/en/enrol_lti.php
enrol/lti/styles.css [deleted file]
enrol/lti/templates/copy_grid.mustache [new file with mode: 0644]
enrol/lti/tests/data_connector_test.php
enrol/lti/tests/sync_members_test.php [new file with mode: 0644]
enrol/lti/version.php
enrol/paypal/ipn.php
filter/mediaplugin/dev/perftest.php
filter/mediaplugin/filter.php
filter/mediaplugin/lang/en/filter_mediaplugin.php
filter/mediaplugin/settings.php [moved from auth/radius/version.php with 64% similarity]
filter/mediaplugin/styles.css
filter/mediaplugin/tests/filter_test.php
grade/grading/form/guide/tests/behat/edit_guide.feature
grade/grading/tests/behat/behat_grading.php
grade/lib.php
grade/report/singleview/tests/behat/bulk_insert_grades.feature
grade/tests/behat/grade_point_maximum.feature
grade/tests/behat/grade_scales.feature
grade/tests/behat/grade_single_item_scales.feature
group/index.php
install/lang/kab/langconfig.php [new file with mode: 0644]
iplookup/tests/geoip_test.php
lang/en/admin.php
lang/en/auth.php
lang/en/cache.php
lang/en/deprecated.txt
lang/en/grades.php
lang/en/media.php
lang/en/moodle.php
lang/en/plugin.php
lang/en/role.php
lang/en/webservice.php
lib/adminlib.php
lib/amd/build/chart_output_chartjs.min.js
lib/amd/src/chart_output_chartjs.js
lib/badgeslib.php
lib/behat/classes/partial_named_selector.php
lib/classes/component.php
lib/classes/files/curl_security_helper.php [new file with mode: 0644]
lib/classes/files/curl_security_helper_base.php [new file with mode: 0644]
lib/classes/filetypes.php
lib/classes/plugin_manager.php
lib/classes/plugininfo/media.php [new file with mode: 0644]
lib/classes/session/manager.php
lib/classes/task/send_failed_login_notifications_task.php
lib/classes/user.php
lib/classes/useragent.php
lib/completionlib.php
lib/db/access.php
lib/db/caches.php
lib/db/install.php
lib/db/install.xml
lib/db/services.php
lib/db/upgrade.php
lib/editor/tinymce/plugins/moodlemedia/preview.php
lib/externallib.php
lib/filelib.php
lib/filestorage/file_storage.php
lib/filestorage/zip_archive.php
lib/flowplayer/LICENSE.txt [deleted file]
lib/flowplayer/README.txt [deleted file]
lib/flowplayer/README_audio.txt [deleted file]
lib/flowplayer/flowplayer-3.2.13.js [deleted file]
lib/flowplayer/flowplayer-3.2.13.min.js [deleted file]
lib/flowplayer/flowplayer-3.2.18.swf [deleted file]
lib/flowplayer/flowplayer-3.2.18.swf.bin [deleted file]
lib/flowplayer/flowplayer.audio-3.2.11.swf [deleted file]
lib/flowplayer/flowplayer.audio-3.2.11.swf.bin [deleted file]
lib/flowplayer/flowplayer.controls-3.2.16.swf [deleted file]
lib/flowplayer/flowplayer.controls-3.2.16.swf.bin [deleted file]
lib/flowplayer/lib.php [deleted file]
lib/flowplayer/readme_moodle.txt [deleted file]
lib/form/editor.php
lib/form/searchableselector.js [deleted file]
lib/form/searchableselector.php
lib/form/static.php
lib/form/templates/editor_textarea.mustache
lib/form/tests/behat/modgrade_validation.feature
lib/grade/grade_item.php
lib/javascript-static.js
lib/ltiprovider/readme_moodle.txt
lib/ltiprovider/src/ToolProvider/Context.php
lib/ltiprovider/src/ToolProvider/DataConnector/DataConnector_mysql.php
lib/ltiprovider/src/ToolProvider/DataConnector/DataConnector_pdo.php
lib/ltiprovider/src/ToolProvider/ToolConsumer.php
lib/ltiprovider/src/ToolProvider/ToolProvider.php
lib/medialib.php
lib/modinfolib.php
lib/moodlelib.php
lib/navigationlib.php
lib/outputrenderers.php
lib/phpunit/classes/util.php
lib/setuplib.php
lib/templates/copy_box.mustache
lib/templates/settings_link_page.mustache
lib/templates/settings_link_page_single.mustache
lib/tests/behat/behat_general.php
lib/tests/curl_security_helper_test.php [new file with mode: 0644]
lib/tests/filelib_test.php
lib/tests/medialib_test.php
lib/tests/message_test.php
lib/tests/messagelib_test.php
lib/tests/moodlelib_test.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-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-alert/moodle-core-notification-alert-debug.js
lib/yui/build/moodle-core-notification-alert/moodle-core-notification-alert-min.js
lib/yui/build/moodle-core-notification-alert/moodle-core-notification-alert.js
lib/yui/build/moodle-core-notification-confirm/moodle-core-notification-confirm-debug.js
lib/yui/build/moodle-core-notification-confirm/moodle-core-notification-confirm-min.js
lib/yui/build/moodle-core-notification-confirm/moodle-core-notification-confirm.js
lib/yui/src/actionmenu/js/actionmenu.js
lib/yui/src/formchangechecker/js/formchangechecker.js
lib/yui/src/notification/js/alert.js
lib/yui/src/notification/js/confirm.js
login/token.php
media/classes/manager.php [new file with mode: 0644]
media/classes/player.php [new file with mode: 0644]
media/classes/player_external.php [new file with mode: 0644]
media/classes/player_native.php [new file with mode: 0644]
media/player/html5audio/classes/plugin.php [new file with mode: 0644]
media/player/html5audio/lang/en/media_html5audio.php [moved from lib/flowplayer/flowplayer-3.2.18.swf.php with 63% similarity]
media/player/html5audio/pix/icon.png [new file with mode: 0644]
media/player/html5audio/tests/player_test.php [new file with mode: 0644]
media/player/html5audio/version.php [new file with mode: 0644]
media/player/html5video/classes/plugin.php [new file with mode: 0644]
media/player/html5video/lang/en/media_html5video.php [moved from lib/flowplayer/flowplayer.audio-3.2.11.swf.php with 63% similarity]
media/player/html5video/pix/icon.png [new file with mode: 0644]
media/player/html5video/tests/player_test.php [new file with mode: 0644]
media/player/html5video/version.php [new file with mode: 0644]
media/player/swf/classes/plugin.php [new file with mode: 0644]
media/player/swf/lang/en/media_swf.php [new file with mode: 0644]
media/player/swf/pix/icon.png [new file with mode: 0644]
media/player/swf/tests/player_test.php [new file with mode: 0644]
media/player/swf/version.php [moved from lib/flowplayer/flowplayer.controls-3.2.16.swf.php with 62% similarity]
media/player/videojs/amd/build/Youtube.min.js [new file with mode: 0644]
media/player/videojs/amd/build/video.min.js [new file with mode: 0644]
media/player/videojs/amd/src/Youtube.js [new file with mode: 0644]
media/player/videojs/amd/src/video.js [new file with mode: 0644]
media/player/videojs/classes/plugin.php [new file with mode: 0644]
media/player/videojs/fonts/VideoJS.eot [new file with mode: 0644]
media/player/videojs/fonts/VideoJS.svg [new file with mode: 0644]
media/player/videojs/fonts/VideoJS.ttf [new file with mode: 0644]
media/player/videojs/fonts/VideoJS.woff [new file with mode: 0644]
media/player/videojs/lang/en/media_videojs.php [new file with mode: 0644]
media/player/videojs/pix/icon.png [new file with mode: 0644]
media/player/videojs/readme_moodle.txt [new file with mode: 0644]
media/player/videojs/settings.php [new file with mode: 0644]
media/player/videojs/styles.css [new file with mode: 0644]
media/player/videojs/tests/player_test.php [new file with mode: 0644]
media/player/videojs/thirdpartylibs.xml [new file with mode: 0644]
media/player/videojs/version.php [new file with mode: 0644]
media/player/videojs/video-js.swf [new file with mode: 0644]
media/player/videojs/videojs/LICENSE [new file with mode: 0644]
media/player/videojs/videojs/lang/ar.js [new file with mode: 0644]
media/player/videojs/videojs/lang/ba.js [new file with mode: 0644]
media/player/videojs/videojs/lang/bg.js [new file with mode: 0644]
media/player/videojs/videojs/lang/ca.js [new file with mode: 0644]
media/player/videojs/videojs/lang/cs.js [new file with mode: 0644]
media/player/videojs/videojs/lang/da.js [new file with mode: 0644]
media/player/videojs/videojs/lang/de.js [new file with mode: 0644]
media/player/videojs/videojs/lang/el.js [new file with mode: 0644]
media/player/videojs/videojs/lang/en.js [new file with mode: 0644]
media/player/videojs/videojs/lang/es.js [new file with mode: 0644]
media/player/videojs/videojs/lang/fa.js [new file with mode: 0644]
media/player/videojs/videojs/lang/fi.js [new file with mode: 0644]
media/player/videojs/videojs/lang/fr.js [new file with mode: 0644]
media/player/videojs/videojs/lang/hr.js [new file with mode: 0644]
media/player/videojs/videojs/lang/hu.js [new file with mode: 0644]
media/player/videojs/videojs/lang/it.js [new file with mode: 0644]
media/player/videojs/videojs/lang/ja.js [new file with mode: 0644]
media/player/videojs/videojs/lang/ko.js [new file with mode: 0644]
media/player/videojs/videojs/lang/nb.js [new file with mode: 0644]
media/player/videojs/videojs/lang/nl.js [new file with mode: 0644]
media/player/videojs/videojs/lang/nn.js [new file with mode: 0644]
media/player/videojs/videojs/lang/pl.js [new file with mode: 0644]
media/player/videojs/videojs/lang/pt-BR.js [new file with mode: 0644]
media/player/videojs/videojs/lang/ru.js [new file with mode: 0644]
media/player/videojs/videojs/lang/sr.js [new file with mode: 0644]
media/player/videojs/videojs/lang/sv.js [new file with mode: 0644]
media/player/videojs/videojs/lang/tr.js [new file with mode: 0644]
media/player/videojs/videojs/lang/uk.js [new file with mode: 0644]
media/player/videojs/videojs/lang/vi.js [new file with mode: 0644]
media/player/videojs/videojs/lang/zh-CN.js [new file with mode: 0644]
media/player/videojs/videojs/lang/zh-TW.js [new file with mode: 0644]
media/player/vimeo/classes/plugin.php [new file with mode: 0644]
media/player/vimeo/lang/en/media_vimeo.php [new file with mode: 0644]
media/player/vimeo/pix/icon.png [new file with mode: 0644]
media/player/vimeo/tests/player_test.php [new file with mode: 0644]
media/player/vimeo/version.php [new file with mode: 0644]
media/player/youtube/classes/plugin.php [new file with mode: 0644]
media/player/youtube/lang/en/media_youtube.php [new file with mode: 0644]
media/player/youtube/pix/icon.png [new file with mode: 0644]
media/player/youtube/tests/player_test.php [new file with mode: 0644]
media/player/youtube/version.php [new file with mode: 0644]
message/amd/build/message_area_contacts.min.js
message/amd/build/message_area_messages.min.js
message/amd/src/message_area_contacts.js
message/amd/src/message_area_messages.js
message/classes/api.php
message/externallib.php
message/lib.php
message/output/email/lang/en/message_email.php
message/output/email/settings.php [deleted file]
message/output/popup/classes/api.php
message/output/popup/lib.php
message/templates/message_area_messages_area.mustache
message/tests/api_test.php
message/tests/externallib_test.php
message/tests/messagelib_test.php
mod/assign/amd/build/grading_panel.min.js
mod/assign/amd/src/grading_panel.js
mod/assign/backup/moodle2/backup_assign_stepslib.php
mod/assign/backup/moodle2/restore_assign_stepslib.php
mod/assign/classes/event/group_override_created.php [new file with mode: 0644]
mod/assign/classes/event/group_override_deleted.php [new file with mode: 0644]
mod/assign/classes/event/group_override_updated.php [new file with mode: 0644]
mod/assign/classes/event/user_override_created.php [new file with mode: 0644]
mod/assign/classes/event/user_override_deleted.php [new file with mode: 0644]
mod/assign/classes/event/user_override_updated.php [new file with mode: 0644]
mod/assign/classes/group_observers.php [new file with mode: 0644]
mod/assign/db/access.php
mod/assign/db/events.php [new file with mode: 0644]
mod/assign/db/install.xml
mod/assign/db/upgrade.php
mod/assign/externallib.php
mod/assign/feedback/editpdf/tests/behat/annotate_pdf.feature
mod/assign/feedback/editpdf/tests/behat/group_annotations.feature
mod/assign/feedback/editpdf/tests/behat/view_previous_annotations.feature
mod/assign/feedback/file/tests/behat/feedback_file.feature
mod/assign/gradingtable.php
mod/assign/lang/en/assign.php
mod/assign/lib.php
mod/assign/locallib.php
mod/assign/override_form.php [new file with mode: 0644]
mod/assign/overridedelete.php [new file with mode: 0644]
mod/assign/overrideedit.php [new file with mode: 0644]
mod/assign/overrides.php [new file with mode: 0644]
mod/assign/styles.css
mod/assign/templates/grading_navigation.mustache
mod/assign/templates/grading_navigation_user_summary.mustache
mod/assign/tests/behat/allow_another_attempt.feature
mod/assign/tests/behat/assign_course_reset.feature [new file with mode: 0644]
mod/assign/tests/behat/assign_group_override.feature [new file with mode: 0644]
mod/assign/tests/behat/assign_user_override.feature [new file with mode: 0644]
mod/assign/tests/behat/comment_inline.feature
mod/assign/tests/behat/display_error_message_onbadformat.feature
mod/assign/tests/behat/display_grade.feature
mod/assign/tests/behat/edit_previous_feedback.feature
mod/assign/tests/behat/edit_student_submission.feature
mod/assign/tests/behat/filter_by_marker.feature
mod/assign/tests/behat/grading_status.feature
mod/assign/tests/behat/grant_extension.feature
mod/assign/tests/behat/group_submission.feature
mod/assign/tests/behat/outcome_grading.feature
mod/assign/tests/behat/prevent_submission_changes.feature
mod/assign/tests/behat/quickgrading.feature
mod/assign/tests/behat/reopen_locked_submission.feature
mod/assign/tests/behat/rescale_grades.feature
mod/assign/tests/behat/steps_blind_marking.feature
mod/assign/tests/behat/submission_comments.feature
mod/assign/tests/behat/submit_without_group.feature
mod/assign/tests/events_test.php
mod/assign/tests/locallib_test.php
mod/assign/version.php
mod/assign/view.php
mod/book/tests/behat/show_hide_chapters.feature
mod/choice/tests/behat/modify_choice.feature
mod/data/tests/behat/add_entries.feature
mod/data/tests/behat/behat_mod_data.php
mod/feedback/classes/complete_form.php
mod/feedback/edit_form.php
mod/feedback/tests/behat/anonymous.feature
mod/feedback/tests/behat/coursemapping.feature
mod/feedback/tests/behat/groups.feature
mod/feedback/tests/behat/multichoice.feature
mod/feedback/tests/behat/non_anonymous.feature
mod/feedback/tests/behat/question_types.feature
mod/feedback/tests/behat/question_types_non_anon.feature
mod/feedback/tests/behat/show_nonrespondents.feature
mod/forum/externallib.php
mod/forum/lib.php
mod/forum/settings.php
mod/forum/tests/behat/forum_subscriptions_availability.feature
mod/forum/upgrade.txt
mod/lesson/locallib.php
mod/lesson/tests/behat/import_images.feature
mod/lesson/tests/behat/lesson_course_reset.feature
mod/lesson/tests/behat/lesson_group_override.feature
mod/lesson/tests/behat/lesson_user_override.feature
mod/lesson/view.php
mod/lti/amd/build/tool_configure_controller.min.js
mod/lti/amd/src/tool_configure_controller.js
mod/lti/classes/output/tool_configure_page.php
mod/lti/lang/en/deprecated.txt [new file with mode: 0644]
mod/lti/lang/en/lti.php
mod/lti/mod_form.php
mod/lti/templates/cartridge_registration_form.mustache
mod/lti/templates/tool_card.mustache
mod/lti/templates/tool_configure.mustache
mod/lti/templates/tool_list.mustache
mod/lti/templates/tool_proxy_card.mustache
mod/lti/tests/behat/addtool.feature
mod/lti/tests/behat/addtype.feature
mod/lti/tests/behat/contentitem.feature
mod/lti/tests/behat/contentitemregistration.feature
mod/quiz/override_form.php
mod/quiz/renderer.php
mod/quiz/tests/behat/backup.feature
mod/quiz/tests/behat/editing_add.feature
mod/quiz/tests/behat/editing_move_by_click.feature
mod/quiz/tests/behat/editing_remove_question.feature
mod/quiz/tests/behat/editing_repaginate.feature
mod/quiz/tests/behat/editing_require_previous.feature
mod/quiz/tests/behat/editing_section_headings.feature
mod/quiz/tests/behat/editing_set_marks_no_attempts.feature
mod/quiz/tests/behat/editing_set_marks_with_attempts.feature
mod/quiz/tests/behat/quiz_reset.feature
mod/resource/locallib.php
mod/scorm/locallib.php
mod/scorm/mod_form.php
mod/scorm/module.js
mod/scorm/report/basic/classes/report.php
mod/scorm/report/interactions/classes/report.php
mod/scorm/report/objectives/classes/report.php
mod/scorm/styles.css
mod/url/locallib.php
mod/workshop/allocation/manual/tests/behat/behat_workshopallocation_manual.php
mod/workshop/tests/behat/behat_mod_workshop.php
report/security/locallib.php
theme/boost/amd/build/form-display-errors.min.js
theme/boost/amd/src/form-display-errors.js
theme/boost/classes/output/core/admin_renderer.php
theme/boost/classes/output/core_renderer.php
theme/boost/layout/columns1.php
theme/boost/layout/columns2.php
theme/boost/scss/moodle.scss
theme/boost/scss/moodle/blocks.scss
theme/boost/scss/moodle/core.scss
theme/boost/scss/moodle/course.scss
theme/boost/scss/moodle/drawer.scss
theme/boost/scss/moodle/filemanager.scss
theme/boost/scss/moodle/forms.scss
theme/boost/scss/moodle/message.scss
theme/boost/scss/moodle/modules.scss
theme/boost/scss/moodle/responsive-tabs.scss [new file with mode: 0644]
theme/boost/templates/columns1.mustache
theme/boost/templates/columns2.mustache
theme/boost/templates/core/block.mustache
theme/boost/templates/core/filemanager_loginform.mustache
theme/boost/templates/core/settings_link_page.mustache [new file with mode: 0644]
theme/boost/templates/core/settings_link_page_single.mustache [new file with mode: 0644]
theme/boost/templates/core_admin/settings_search_results.mustache
theme/boost/templates/core_form/editor_textarea.mustache
theme/boost/templates/core_form/element-advcheckbox-inline.mustache
theme/boost/templates/core_form/element-advcheckbox.mustache
theme/boost/templates/core_form/element-autocomplete-inline.mustache
theme/boost/templates/core_form/element-checkbox-inline.mustache
theme/boost/templates/core_form/element-checkbox.mustache
theme/boost/templates/core_form/element-radio-inline.mustache
theme/boost/templates/core_form/element-radio.mustache
theme/boost/templates/core_form/element-select-inline.mustache
theme/boost/templates/core_form/element-select.mustache
theme/boost/templates/core_form/element-selectwithlink.mustache
theme/boost/templates/core_form/element-static.mustache
theme/boost/templates/core_form/element-tags-inline.mustache
theme/boost/templates/core_form/element-tags.mustache
theme/boost/templates/core_form/element-template.mustache
theme/boost/templates/mod_assign/grading_navigation.mustache
theme/boost/templates/tool_lp/progress_bar.mustache [new file with mode: 0644]
theme/boost/tests/behat/behat_theme_boost_behat_admin.php
theme/bootstrapbase/less/moodle/bs4-compat.less
theme/bootstrapbase/less/moodle/buttons.less
theme/bootstrapbase/less/moodle/course.less
theme/bootstrapbase/less/moodle/expendable.less
theme/bootstrapbase/less/moodle/message.less
theme/bootstrapbase/less/moodle/tool_usertours.less
theme/bootstrapbase/style/moodle.css
user/edit.php
user/edit_form.php
user/profile/lib.php
version.php
webservice/externallib.php
webservice/lib.php
webservice/renderer.php
webservice/tests/externallib_test.php

index 68293b9..fe5da7b 100644 (file)
@@ -24,7 +24,6 @@ lib/htmlpurifier/
 lib/jabber/
 lib/minify/matthiasmullie-minify/
 lib/minify/matthiasmullie-pathconverter/
-lib/flowplayer/
 lib/pear/Auth/RADIUS.php
 lib/pear/Crypt/CHAP.php
 lib/pear/HTML/Common.php
@@ -57,6 +56,8 @@ lib/amd/src/chartjs-lazy.js
 lib/maxmind/GeoIp2/
 lib/maxmind/MaxMind/
 lib/ltiprovider/
+media/player/videojs/amd/src/
+media/player/videojs/videojs/
 mod/assign/feedback/editpdf/fpdi/
 repository/s3/S3.php
 theme/boost/scss/bootstrap/
index 383c520..cafa933 100644 (file)
@@ -25,7 +25,6 @@ lib/htmlpurifier/
 lib/jabber/
 lib/minify/matthiasmullie-minify/
 lib/minify/matthiasmullie-pathconverter/
-lib/flowplayer/
 lib/pear/Auth/RADIUS.php
 lib/pear/Crypt/CHAP.php
 lib/pear/HTML/Common.php
@@ -58,6 +57,8 @@ lib/amd/src/chartjs-lazy.js
 lib/maxmind/GeoIp2/
 lib/maxmind/MaxMind/
 lib/ltiprovider/
+media/player/videojs/amd/src/
+media/player/videojs/videojs/
 mod/assign/feedback/editpdf/fpdi/
 repository/s3/S3.php
 theme/boost/scss/bootstrap/
diff --git a/admin/media.php b/admin/media.php
new file mode 100644 (file)
index 0000000..d6886a0
--- /dev/null
@@ -0,0 +1,79 @@
+<?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/>.
+
+/**
+ * Enrol config manipulation script.
+ *
+ * @package    core
+ * @subpackage media
+ * @copyright  2016 Marina Glancy
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+define('NO_OUTPUT_BUFFERING', true);
+
+require_once('../config.php');
+require_once($CFG->libdir.'/adminlib.php');
+
+$action  = required_param('action', PARAM_ALPHANUMEXT);
+$media   = required_param('media', PARAM_PLUGIN);
+$confirm = optional_param('confirm', 0, PARAM_BOOL);
+
+$PAGE->set_url('/admin/media.php');
+$PAGE->set_context(context_system::instance());
+
+require_login();
+require_capability('moodle/site:config', context_system::instance());
+require_sesskey();
+
+$plugins = core_plugin_manager::instance()->get_plugins_of_type('media');
+$sortorder = array_values(\core\plugininfo\media::get_enabled_plugins());
+
+$return = new moodle_url('/admin/settings.php', array('section' => 'managemediaplayers'));
+
+if (!array_key_exists($media, $plugins)) {
+    redirect($return);
+}
+
+switch ($action) {
+    case 'disable':
+        $plugins[$media]->set_enabled(false);
+        break;
+
+    case 'enable':
+        $plugins[$media]->set_enabled(true);
+        break;
+
+    case 'up':
+        if (($pos = array_search($media, $sortorder)) > 0) {
+            $tmp = $sortorder[$pos - 1];
+            $sortorder[$pos - 1] = $sortorder[$pos];
+            $sortorder[$pos] = $tmp;
+            \core\plugininfo\media::set_enabled_plugins($sortorder);
+        }
+        break;
+
+    case 'down':
+        if ((($pos = array_search($media, $sortorder)) !== false) && ($pos < count($sortorder) - 1)) {
+            $tmp = $sortorder[$pos + 1];
+            $sortorder[$pos + 1] = $sortorder[$pos];
+            $sortorder[$pos] = $tmp;
+            \core\plugininfo\media::set_enabled_plugins($sortorder);
+        }
+        break;
+}
+
+redirect($return);
index 52cb560..6924e61 100644 (file)
@@ -41,7 +41,7 @@ if (!empty($disable) && confirm_sesskey()) {
     if (!$processor = $DB->get_record('message_processors', array('id'=>$disable))) {
         print_error('outputdoesnotexist', 'message');
     }
-    $DB->set_field('message_processors', 'enabled', '0', array('id'=>$processor->id));      // Disable output
+    \core_message\api::update_processor_status($processor, 0);     // Disable output.
     core_plugin_manager::reset_caches();
 }
 
@@ -49,7 +49,7 @@ if (!empty($enable) && confirm_sesskey()) {
     if (!$processor = $DB->get_record('message_processors', array('id'=>$enable))) {
         print_error('outputdoesnotexist', 'message');
     }
-    $DB->set_field('message_processors', 'enabled', '1', array('id'=>$processor->id));      // Enable output
+    \core_message\api::update_processor_status($processor, 1);      // Enable output.
     core_plugin_manager::reset_caches();
 }
 
index a9339b0..5769e6d 100644 (file)
@@ -60,7 +60,8 @@ class mnet_simple_host_form extends moodleform {
         }
         if ($host = $DB->get_record('mnet_host', array('wwwroot' => $wwwroot))) {
             global $CFG;
-            return array('wwwroot' => get_string('hostexists', 'mnet', $CFG->wwwroot . '/admin/mnet/peers.php?hostid=' . $host->id));
+            return array('wwwroot' => get_string('hostexists', 'mnet',
+                new moodle_url('/admin/mnet/peers.php', array('hostid' => $host->id))));
         }
         return array();
     }
index df1f6e2..559d2f4 100644 (file)
@@ -109,7 +109,7 @@ if (!empty($hostid)) {
     $mnet_peer->set_id($hostid);
     echo $OUTPUT->header();
     $currenttab = 'mnetdetails';
-    require_once($CFG->dirroot . '/admin/mnet/tabs.php');
+    require_once($CFG->dirroot . '/' . $CFG->admin . '/mnet/tabs.php');
 
     if ($hostid != $CFG->mnet_all_hosts_id) {
         $mnet_peer->currentkey = mnet_get_public_key($mnet_peer->wwwroot, $mnet_peer->application);
@@ -144,7 +144,7 @@ if (empty($noreviewform) && $id = optional_param('id', 0, PARAM_INT)) {
     // we're editing an existing one, so set up the tabs
     $currenttab = 'mnetdetails';
     $mnet_peer->set_id($id);
-    require_once($CFG->dirroot . '/admin/mnet/tabs.php');
+    require_once($CFG->dirroot . '/' . $CFG->admin . '/mnet/tabs.php');
 } else if (empty($noreviewform) && ($wwwroot = optional_param('wwwroot', '', PARAM_URL)) && ($applicationid = optional_param('applicationid', 0, PARAM_INT))) {
     $application = $DB->get_field('mnet_application', 'name', array('id'=>$applicationid));
     $mnet_peer->bootstrap($wwwroot, null, $application);
index 24ba79c..a27f162 100644 (file)
@@ -26,7 +26,7 @@
 
 require(__DIR__.'/../../config.php');
 require_once($CFG->libdir.'/adminlib.php');
-require_once($CFG->dirroot . '/admin/mnet/profilefields_form.php');
+require_once($CFG->dirroot . '/' . $CFG->admin .'/mnet/profilefields_form.php');
 $mnet = get_mnet_environment();
 
 require_login();
index ea588cd..79e46e9 100644 (file)
@@ -27,7 +27,7 @@
 
 require(__DIR__.'/../../config.php');
 require_once($CFG->libdir.'/adminlib.php');
-require_once($CFG->dirroot . '/admin/mnet/services_form.php');
+require_once($CFG->dirroot . '/' . $CFG->admin . '/mnet/services_form.php');
 $mnet = get_mnet_environment();
 
 require_login();
@@ -82,7 +82,7 @@ if ($formdata = $mform->get_data()) {
 
 echo $OUTPUT->header();
 $currenttab = 'mnetservices';
-require_once($CFG->dirroot . '/admin/mnet/tabs.php');
+require_once($CFG->dirroot . '/' . $CFG->admin . '/mnet/tabs.php');
 echo $OUTPUT->box_start();
 $s = mnet_get_service_info($mnet_peer, false); // basic data only
 $mform->set_data($s);
index 2b66c9f..d98e379 100644 (file)
@@ -32,6 +32,8 @@ $getroles = optional_param('getroles', 0, PARAM_BOOL);
 
 list($context, $course, $cm) = get_context_info_array($contextid);
 
+$PAGE->set_context($context);
+
 require_login($course, false, $cm);
 require_capability('moodle/role:review', $context);
 require_sesskey();
index 9f339d8..76260c7 100644 (file)
@@ -132,7 +132,7 @@ class core_role_permissions_table extends core_role_capability_table_base {
 
         $risks = $this->get_risks($capability);
 
-        $contents = html_writer::tag('td', $risks, array('class' => 'risks'));
+        $contents = html_writer::tag('td', $risks, array('class' => 'risks text-nowrap'));
         $contents .= html_writer::tag('td', $neededroles, array('class' => 'allowedroles'));
         $contents .= html_writer::tag('td', $forbiddenroles, array('class' => 'forbiddenroles'));
         return $contents;
index 0e9a531..7dd8e2c 100644 (file)
@@ -7,7 +7,8 @@ require_once($CFG->libdir.'/adminlib.php');
 
 $query = trim(optional_param('query', '', PARAM_NOTAGS));  // Search string
 
-$PAGE->set_context(context_system::instance());
+$context = context_system::instance();
+$PAGE->set_context($context);
 
 admin_externalpage_setup('search', '', array('query' => $query)); // now hidden page
 
@@ -18,7 +19,8 @@ $errormsg  = '';
 $focus = '';
 
 // now we'll deal with the case that the admin has submitted the form with changed settings
-if ($data = data_submitted() and confirm_sesskey()) {
+if ($data = data_submitted() and confirm_sesskey() and isset($data->action) and $data->action == 'save-settings') {
+    require_capability('moodle/site:config', $context);
     if (admin_write_settings($data)) {
         redirect($PAGE->url, get_string('changessaved'), null, \core\output\notification::NOTIFY_SUCCESS);
     }
@@ -45,14 +47,20 @@ if ($errormsg !== '') {
     echo $OUTPUT->notification($statusmsg, 'notifysuccess');
 }
 
-require_once("admin_settings_search_form.php");
-$form = new admin_settings_search_form();
-$form->display();
-echo '<hr>';
+$showsettingslinks = true;
 
-if ($query) {
-    echo admin_search_settings_html($query);
-} else {
+if (has_capability('moodle/site:config', $context)) {
+    require_once("admin_settings_search_form.php");
+    $form = new admin_settings_search_form();
+    $form->display();
+    echo '<hr>';
+    if ($query) {
+        echo admin_search_settings_html($query);
+        $showsettingslinks = false;
+    }
+}
+
+if ($showsettingslinks) {
     $node = $PAGE->settingsnav->find('root', navigation_node::TYPE_SITE_ADMIN);
     if ($node) {
         echo $OUTPUT->render_from_template('core/settings_link_page', ['node' => $node]);
index 7ee3f70..398c777 100644 (file)
@@ -196,49 +196,6 @@ preferences,moodle|/user/preferences.php|preferences',
     $ADMIN->add('appearance', new admin_externalpage('resetemoticons', new lang_string('emoticonsreset', 'admin'),
         new moodle_url('/admin/resetemoticons.php'), 'moodle/site:config', true));
 
-
-    // The "media" subpage.
-    $temp = new admin_settingpage('mediasettings', get_string('mediasettings', 'core_media'));
-
-    $temp->add(new admin_setting_heading('mediaformats', get_string('mediaformats', 'core_media'),
-            format_text(get_string('mediaformats_desc', 'core_media'), FORMAT_MARKDOWN)));
-
-    // External services.
-    $temp->add(new admin_setting_configcheckbox('core_media_enable_youtube',
-            get_string('siteyoutube', 'core_media'), get_string('siteyoutube_desc', 'core_media'), 1));
-    $temp->add(new admin_setting_configcheckbox('core_media_enable_vimeo',
-            get_string('sitevimeo', 'core_media'), get_string('sitevimeo_desc', 'core_media'), 0));
-
-    // Options which require Flash.
-    $temp->add(new admin_setting_configcheckbox('core_media_enable_mp3',
-            get_string('mp3audio', 'core_media'), get_string('mp3audio_desc', 'core_media'), 1));
-    $temp->add(new admin_setting_configcheckbox('core_media_enable_flv',
-            get_string('flashvideo', 'core_media'), get_string('flashvideo_desc', 'core_media'), 1));
-    $temp->add(new admin_setting_configcheckbox('core_media_enable_swf',
-            get_string('flashanimation', 'core_media'), get_string('flashanimation_desc', 'core_media'), 1));
-
-    // HTML 5 media.
-    // Audio now enabled by default so that it can provide a fallback for mp3 on devices without flash.
-    $temp->add(new admin_setting_configcheckbox('core_media_enable_html5audio',
-            get_string('html5audio', 'core_media'), get_string('html5audio_desc', 'core_media'), 1));
-    // Video now enabled by default so it can provide mp4 support.
-    $temp->add(new admin_setting_configcheckbox('core_media_enable_html5video',
-            get_string('html5video', 'core_media'), get_string('html5video_desc', 'core_media'), 1));
-
-    // Legacy players.
-    $temp->add(new admin_setting_heading('legacymediaformats',
-            get_string('legacyheading', 'core_media'), get_string('legacyheading_desc', 'core_media')));
-
-    $temp->add(new admin_setting_configcheckbox('core_media_enable_qt',
-            get_string('legacyquicktime', 'core_media'), get_string('legacyquicktime_desc', 'core_media'), 1));
-    $temp->add(new admin_setting_configcheckbox('core_media_enable_wmp',
-            get_string('legacywmp', 'core_media'), get_string('legacywmp_desc', 'core_media'), 1));
-    $temp->add(new admin_setting_configcheckbox('core_media_enable_rm',
-            get_string('legacyreal', 'core_media'), get_string('legacyreal_desc', 'core_media'), 1));
-
-    $ADMIN->add('appearance', $temp);
-
-
     // "documentation" settingpage
     $temp = new admin_settingpage('documentation', new lang_string('moodledocs'));
     $temp->add(new admin_setting_configtext('docroot', new lang_string('docroot', 'admin'), new lang_string('configdocroot', 'admin'), 'http://docs.moodle.org', PARAM_URL));
index 2dbff19..bd759a7 100644 (file)
@@ -215,6 +215,28 @@ if ($hassiteconfig) {
         $plugin->load_settings($ADMIN, 'filtersettings', $hassiteconfig);
     }
 
+    // Media players.
+    $ADMIN->add('modules', new admin_category('mediaplayers', new lang_string('type_media_plural', 'plugin')));
+    $temp = new admin_settingpage('managemediaplayers', new lang_string('managemediaplayers', 'media'));
+    $temp->add(new admin_setting_heading('mediaformats', get_string('mediaformats', 'core_media'),
+        format_text(get_string('mediaformats_desc', 'core_media'), FORMAT_MARKDOWN)));
+    $temp->add(new admin_setting_managemediaplayers());
+    $temp->add(new admin_setting_heading('managemediaplayerscommonheading', new lang_string('commonsettings', 'admin'), ''));
+    $temp->add(new admin_setting_configtext('media_default_width',
+        new lang_string('defaultwidth', 'core_media'), new lang_string('defaultwidthdesc', 'core_media'),
+        400, PARAM_INT, 10));
+    $temp->add(new admin_setting_configtext('media_default_height',
+        new lang_string('defaultheight', 'core_media'), new lang_string('defaultheightdesc', 'core_media'),
+        300, PARAM_INT, 10));
+    $ADMIN->add('mediaplayers', $temp);
+
+    $plugins = core_plugin_manager::instance()->get_plugins_of_type('media');
+    core_collator::asort_objects_by_property($plugins, 'displayname');
+    foreach ($plugins as $plugin) {
+        /** @var \core\plugininfo\media $plugin */
+        $plugin->load_settings($ADMIN, 'mediaplayers', $hassiteconfig);
+    }
+
     // Data format settings.
     $ADMIN->add('modules', new admin_category('dataformatsettings', new lang_string('dataformats')));
     $temp = new admin_settingpage('managedataformats', new lang_string('managedataformats'));
index c892566..1d89d42 100644 (file)
@@ -118,8 +118,15 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
     $temp->add(new admin_setting_configcheckbox('cookiehttponly', new lang_string('cookiehttponly', 'admin'), new lang_string('configcookiehttponly', 'admin'), 0));
     $temp->add(new admin_setting_configcheckbox('allowframembedding', new lang_string('allowframembedding', 'admin'), new lang_string('allowframembedding_help', 'admin'), 0));
     $temp->add(new admin_setting_configcheckbox('loginpasswordautocomplete', new lang_string('loginpasswordautocomplete', 'admin'), new lang_string('loginpasswordautocomplete_help', 'admin'), 0));
-    $ADMIN->add('security', $temp);
 
+    // Settings elements used by the \core\files\curl_security_helper class.
+    $temp->add(new admin_setting_configmixedhostiplist('curlsecurityblockedhosts',
+               new lang_string('curlsecurityblockedhosts', 'admin'),
+               new lang_string('curlsecurityblockedhostssyntax', 'admin'), ""));
+    $temp->add(new admin_setting_configportlist('curlsecurityallowedport',
+               new lang_string('curlsecurityallowedport', 'admin'),
+               new lang_string('curlsecurityallowedportsyntax', 'admin'), ""));
+    $ADMIN->add('security', $temp);
 
     // "notifications" settingpage
     $temp = new admin_settingpage('notifications', new lang_string('notifications', 'admin'));
index aae21f9..3c56ff1 100644 (file)
@@ -213,6 +213,60 @@ $ADMIN->add('server', $temp);
 $ADMIN->add('server', new admin_externalpage('adminregistration', new lang_string('hubs', 'admin'),
     "$CFG->wwwroot/$CFG->admin/registration/index.php"));
 
+// E-mail settings.
+$ADMIN->add('server', new admin_category('email', new lang_string('categoryemail', 'admin')));
+
+$temp = new admin_settingpage('outgoingmailconfig', new lang_string('outgoingmailconfig', 'admin'));
+
+$temp->add(new admin_setting_heading('smtpheading', new lang_string('smtp', 'admin'),
+            new lang_string('smtpdetail', 'admin')));
+$temp->add(new admin_setting_configtext('smtphosts', new lang_string('smtphosts', 'admin'),
+            new lang_string('configsmtphosts', 'admin'), '', PARAM_RAW));
+$options = array('' => new lang_string('none', 'admin'), 'ssl' => 'SSL', 'tls' => 'TLS');
+$temp->add(new admin_setting_configselect('smtpsecure', new lang_string('smtpsecure', 'admin'),
+            new lang_string('configsmtpsecure', 'admin'), '', $options));
+$authtypeoptions = array('LOGIN' => 'LOGIN', 'PLAIN' => 'PLAIN', 'NTLM' => 'NTLM', 'CRAM-MD5' => 'CRAM-MD5');
+$temp->add(new admin_setting_configselect('smtpauthtype', new lang_string('smtpauthtype', 'admin'),
+            new lang_string('configsmtpauthtype', 'admin'), 'LOGIN', $authtypeoptions));
+$temp->add(new admin_setting_configtext('smtpuser', new lang_string('smtpuser', 'admin'),
+            new lang_string('configsmtpuser', 'admin'), '', PARAM_NOTAGS));
+$temp->add(new admin_setting_configpasswordunmask('smtppass', new lang_string('smtppass', 'admin'),
+            new lang_string('configsmtpuser', 'admin'), ''));
+$temp->add(new admin_setting_configtext('smtpmaxbulk', new lang_string('smtpmaxbulk', 'admin'),
+           new lang_string('configsmtpmaxbulk', 'admin'), 1, PARAM_INT));
+$temp->add(new admin_setting_heading('noreplydomainheading', new lang_string('noreplydomain', 'admin'),
+        new lang_string('noreplydomaindetail', 'admin')));
+$temp->add(new admin_setting_configtext('noreplyaddress', new lang_string('noreplyaddress', 'admin'),
+          new lang_string('confignoreplyaddress', 'admin'), 'noreply@' . get_host_from_url($CFG->wwwroot), PARAM_NOTAGS));
+$temp->add(new admin_setting_configtextarea('allowedemaildomains',
+        new lang_string('allowedemaildomains', 'admin'),
+        new lang_string('configallowedemaildomains', 'admin'),
+        ''));
+$temp->add(new admin_setting_heading('emaildoesnotfit', new lang_string('doesnotfit', 'admin'),
+        new lang_string('doesnotfitdetail', 'admin')));
+$charsets = get_list_of_charsets();
+unset($charsets['UTF-8']); // Not needed here.
+$options = array();
+$options['0'] = 'UTF-8';
+$options = array_merge($options, $charsets);
+$temp->add(new admin_setting_configselect('sitemailcharset', new lang_string('sitemailcharset', 'admin'),
+          new lang_string('configsitemailcharset','admin'), '0', $options));
+$temp->add(new admin_setting_configcheckbox('allowusermailcharset', new lang_string('allowusermailcharset', 'admin'),
+          new lang_string('configallowusermailcharset', 'admin'), 0));
+$temp->add(new admin_setting_configcheckbox('allowattachments', new lang_string('allowattachments', 'admin'),
+          new lang_string('configallowattachments', 'admin'), 1));
+$options = array('LF' => 'LF', 'CRLF' => 'CRLF');
+$temp->add(new admin_setting_configselect('mailnewline', new lang_string('mailnewline', 'admin'),
+          new lang_string('configmailnewline', 'admin'), 'LF', $options));
+
+$choices = array(new lang_string('never', 'admin'),
+                 new lang_string('always', 'admin'),
+                 new lang_string('onlynoreply', 'admin'));
+$temp->add(new admin_setting_configselect('emailfromvia', new lang_string('emailfromvia', 'admin'),
+          new lang_string('configemailfromvia', 'admin'), 1, $choices));
+
+$ADMIN->add('email', $temp);
+
 // "update notifications" settingpage
 if (empty($CFG->disableupdatenotifications)) {
     $temp = new admin_settingpage('updatenotifications', new lang_string('updatenotifications', 'core_admin'));
index 59a6102..5d4495c 100644 (file)
@@ -47,4 +47,4 @@ $ADMIN->add('root', new admin_category('development', new lang_string('developme
 $ADMIN->add('root', new admin_category('unsupported', new lang_string('unsupported', 'admin'), true));
 
 // hidden search script
-$ADMIN->add('root', new admin_externalpage('search', new lang_string('search', 'admin'), "$CFG->wwwroot/$CFG->admin/search.php", 'moodle/site:config', true));
+$ADMIN->add('root', new admin_externalpage('search', new lang_string('search', 'admin'), "$CFG->wwwroot/$CFG->admin/search.php", 'moodle/site:configview', true));
index c6f7bbb..78b6205 100644 (file)
@@ -37,6 +37,7 @@
 <form action="{{actionurl}}" method="post" id="adminsettings">
     <div>
         <input type="hidden" name="sesskey" value="{{sesskey}}">
+        <input type="hidden" name="action" value="save-settings">
     </div>
     <fieldset>
         <div class="clearer"></div>
index 9edf445..b867c58 100644 (file)
@@ -60,9 +60,9 @@ Feature: Verify that all form fields values can be get and set
       | HTML format | Student page contents |
     And I press "Save"
     Then I should see "Student page contents" in the "region-main" "region"
-    And I follow "Edit"
+    And  I click on "Edit" "link" in the "Administration" "block"
     # Select (multi-select) - Checking "I set the field".
-    And I follow "Edit settings"
+    And I click on "Edit settings" "link" in the "Administration" "block"
     And I expand all fieldsets
     # Checkbox - Checking "I set the field".
     And I set the field "Display description on course page" to "1"
@@ -75,7 +75,7 @@ Feature: Verify that all form fields values can be get and set
     And I press "Save and return to course"
     And I should see "Test this one"
     And I follow "Test this one"
-    And I follow "Edit settings"
+    And I click on "Edit settings" "link" in the "Administration" "block"
     # Checkbox - Checking "the field matches value" and "the following fields match these values".
     And the following fields match these values:
       | Display description on course page | 1 |
@@ -91,7 +91,7 @@ Feature: Verify that all form fields values can be get and set
     # Select (simple) - Checking "I set the field".
     And I set the field "Group mode" to "Separate groups"
     And I press "Save and display"
-    And I follow "Edit settings"
+    And I click on "Edit settings" "link" in the "Administration" "block"
     And the following fields match these values:
       | Default format | NWiki |
       | Group mode | Separate groups |
@@ -158,7 +158,7 @@ Feature: Verify that all form fields values can be get and set
     And the "available[day]" "field" should be enabled
     And the field "deadline[enabled]" matches value "1"
     And I press "Save and display"
-    And I follow "Edit settings"
+    And I click on "Edit settings" "link" in the "Administration" "block"
     And the field "available[enabled]" matches value "1"
     And the "available[day]" "field" should be enabled
     And the field "deadline[enabled]" matches value "1"
index bf43258..3ea368c 100644 (file)
@@ -184,6 +184,8 @@ class controller {
 
         if ($updated) {
             $this->info[] = get_string('langupdatecomplete', 'tool_langimport');
+            // The strings have been changed so we need to purge their cache to ensure users see the changes.
+            get_string_manager()->reset_caches();
         } else {
             $this->info[] = get_string('nolangupdateneeded', 'tool_langimport');
         }
index f249b03..6d50e26 100644 (file)
Binary files a/admin/tool/lp/amd/build/menubar.min.js and b/admin/tool/lp/amd/build/menubar.min.js differ
index 0434b56..76595fe 100644 (file)
@@ -258,7 +258,7 @@ define(['jquery'], function($) {
     Menubar.prototype.setOpenDirection = function() {
         var pos = this.menuRoot.offset();
         var isRTL = $(document.body).hasClass('dir-rtl');
-        var openLeft = false;
+        var openLeft = true;
         var heightmenuRoot = this.rootMenus.outerHeight();
         var widthmenuRoot = this.rootMenus.outerWidth();
         // Sometimes the menuMinWidth is not enough to figure out if menu exceeds the window width.
index 7f1ba9c..aed8874 100644 (file)
@@ -142,7 +142,7 @@ function tool_lp_coursemodule_standard_elements($formwrapper, $mform) {
     $mform->addElement('header', 'competenciessection', get_string('competencies', 'core_competency'));
 
     MoodleQuickForm::registerElementType('course_competencies',
-                                         "$CFG->dirroot/admin/tool/lp/classes/course_competencies_form_element.php",
+                                         "$CFG->dirroot/$CFG->admin/tool/lp/classes/course_competencies_form_element.php",
                                          'tool_lp_course_competencies_form_element');
     $cmid = null;
     if ($cm = $formwrapper->get_coursemodule()) {
@@ -155,7 +155,7 @@ function tool_lp_coursemodule_standard_elements($formwrapper, $mform) {
     $mform->addElement('course_competencies', 'competencies', get_string('modcompetencies', 'tool_lp'), $options);
     $mform->addHelpButton('competencies', 'modcompetencies', 'tool_lp');
     MoodleQuickForm::registerElementType('course_competency_rule',
-                                         "$CFG->dirroot/admin/tool/lp/classes/course_competency_rule_form_element.php",
+                                         "$CFG->dirroot/$CFG->admin/tool/lp/classes/course_competency_rule_form_element.php",
                                          'tool_lp_course_competency_rule_form_element');
     // Reuse the same options.
     $mform->addElement('course_competency_rule', 'competency_rule', get_string('uponcoursemodulecompletion', 'tool_lp'), $options);
index e811b9a..73e7313 100644 (file)
 }
 
 .tool-lp-menu.tool-lp-menu-open-left .tool-lp-sub-menu {
-    margin-left: -120px;
+    left: auto;
+    right: 0;
 }
 
 /** This highlighting is copied from bootstrap - but can be overridden by a theme */
index 1f307a7..7ebb157 100644 (file)
@@ -15,6 +15,8 @@
     along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 }}
 {{!
+    @template tool_lp/action_selector
+
     Select an action to execute.
 
     Classes required for JS:
     * choices - List of possible actions
     * confirm - Text for button confirms
     * cancel -  Text for button cancel
- }}
+
+    Example context (json):
+    {
+        "message": "Message",
+        "choices": [
+            { "value": "1", "text": "One" },
+            { "value": "2", "text": "Two" }
+        ],
+        "confirm": "Confirm",
+        "cancel": "Cancel"
+    }
+}}
 <div data-region="action-selector">
     <div data-region="action-selector-message">
        {{message}}<br>
     </div><br>
     <div data-region="action-selector-radio-buttons">
        {{#choices}}
-        <input id="action-selection-option-{{value}}" type="radio" name="choice" value="{{value}}"/><label for="action-selection-option-{{value}}">{{text}}</label><br>
+        <input id="action-selection-option-{{value}}" type="radio" class="m-r-1" name="choice" value="{{value}}"/><label for="action-selection-option-{{value}}">{{text}}</label><br>
        {{/choices}}
     </div><br>
     <div data-region="action_selector-buttons">
-       <input type="button" data-action="action-selector-confirm" value="{{confirm}}"/>
-       <input type="button" data-action="action-selector-cancel" value="{{cancel}}"/>
+       <input type="button" data-action="action-selector-confirm" class="btn btn-primary" value="{{confirm}}"/>
+       <input type="button" data-action="action-selector-cancel" class="btn btn-secondary" value="{{cancel}}"/>
     </div>
 </div>
index e2ac064..a93697a 100644 (file)
@@ -45,6 +45,7 @@
     * template
     * uniqid
 
+    // This template has no example context because it would trigger real updates to the DB.
     Example context (json):
     {
     }
index d6ae8e6..06b5e24 100644 (file)
@@ -15,6 +15,8 @@
     along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 }}
 {{!
+    @template tool_lp/competencies_move_tree
+
     Manage competencies template.
 
     Classes required for JS:
     Context variables required for this template:
     * framework -
     * competencies - array of objects containing id, shortname, idnumber, sortorder, parentid, competencyframeworkid, path
+
+    Example context (json):
+    {
+        "framework": {
+            "shortname":"framework"
+        },
+        "competencies": [
+            { "name": "Competency", "id": 1 }
+        ]
+    }
 }}
 <div data-region="competencymovetree" >
 <label>{{#str}}selectcompetencymovetarget, tool_lp{{/str}}</label>
@@ -41,7 +53,8 @@
 </ul>
 </div>
 
-<div data-region="move-buttons">
-    <input type="button" data-action="move" value="{{#str}}move{{/str}}"/>
-    <input type="button" data-action="cancel" value="{{#str}}cancel{{/str}}"/>
+<div data-region="move-buttons" class="pull-xs-right">
+    <input type="button" data-action="move" class="btn btn-primary" value="{{#str}}move{{/str}}"/>
+    <input type="button" data-action="cancel" class="btn btn-secondary" value="{{#str}}cancel{{/str}}"/>
 </div>
+<div class="clearfix"></div>
index 75c2282..73ded30 100644 (file)
@@ -1,3 +1,54 @@
+{{!
+    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/>.
+}}
+{{!
+    @template tool_lp/competencies_tree
+
+    Recursively build a competencies tree.
+
+    Classes required for JS:
+
+    Data attibutes required for JS:
+    * data-enhance=movetree
+
+    Context variables required for this template:
+    * id, shortname, idnumber, sortorder, parentid, competencyframeworkid, path, children
+
+    Example context (json):
+    {
+        "id": 1,
+        "shortname": "short",
+        "idnumber": "SHORT",
+        "sortorder": 1,
+        "parentid": 0,
+        "competencyframeworkid": 1,
+        "path": "/",
+        "haschildren": true,
+        "children": [{
+            "id": 2,
+            "shortname": "child",
+            "idnumber": "CHILD",
+            "sortorder": 1,
+            "parentid": 1,
+            "competencyframeworkid": 1,
+            "path": "/1/",
+            "children": []
+        }]
+    }
+}}
 <li data-id="{{id}}">
     {{#canmanage}}
     <span draggable="true">
index d138fe1..ed911f7 100644 (file)
@@ -1,4 +1,49 @@
-<ul data-enhance="tree">
+{{!
+    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/>.
+}}
+{{!
+    @template tool_lp/competencies_tree_root
+
+    Recursively build a competencies tree.
+
+    Classes required for JS:
+
+    Data attibutes required for JS:
+    * data-enhance=movetree
+
+    Context variables required for this template:
+    * id, shortname, idnumber, sortorder, parentid, competencyframeworkid, path, children
+
+    Example context (json):
+    {
+        "shortname": "short",
+        "haschildren": true,
+        "competencies": [{
+            "id": 2,
+            "shortname": "child",
+            "idnumber": "CHILD",
+            "sortorder": 1,
+            "parentid": 1,
+            "competencyframeworkid": 1,
+            "path": "/1/",
+            "children": []
+        }]
+    }
+}}
+<ul data-enhance="tree" class="competency-tree">
     <li><span>{{{shortname}}}</span>
         <ul>
             {{#competencies}}
index 6b47042..20060b7 100644 (file)
@@ -1,26 +1,59 @@
+{{!
+    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/>.
+}}
+{{!
+    @template tool_lp/competency_grader
+
+    Template for grading a competency.
+
+    Classes required for JS:
+      None
+
+    Data required for JS:
+    * ratings - list of value, name selected for valid ratings
+
+    Example context (json):
+    {
+        "ratings": [
+            {"name": "Bad", "value": 0, "selected": true},
+            {"name": "OK", "value": 1},
+            {"name": "Good", "value": 2}
+        ]
+    }
+}}
 <div class="competency-grader" data-region="competency-grader">
     <form>
         <div class="content">
             <div data-region="rating">
                 <label for="rating_{{uniqid}}">{{#str}}rating, tool_lp{{/str}}</label>
-                <select name="rating" id="rating_{{uniqid}}">
+                <select name="rating" id="rating_{{uniqid}}" class="custom-select">
                     {{#ratings}}
                         <option value="{{value}}" {{#selected}}selected{{/selected}}>{{name}}</option>
                     {{/ratings}}
                 </select>
             </div>
-            <div data-region="comment">
+            <div data-region="comment" class="m-t-1">
                 <label for="comment_{{uniqid}}">{{#str}}ratecomment, tool_lp{{/str}}</label>
-                <textarea name="comment" id="comment_{{uniqid}}"></textarea>
+                <textarea name="comment" id="comment_{{uniqid}}" class="form-control m-b-1"></textarea>
             </div>
         </div>
-        <div data-region="footer">
-            <div class="pull-right">
-                <input type="button" data-action="rate" value="{{#str}}rate, tool_lp{{/str}}" class="btn">
-            </div>
-            <div>
-                <button data-action="cancel" class="btn btn-link">{{#str}}cancel{{/str}}</button>
-            </div>
+        <div data-region="footer" class="pull-xs-right">
+            <input type="button" data-action="rate" value="{{#str}}rate, tool_lp{{/str}}" class="btn btn-primary">
+            <button data-action="cancel" class="btn btn-secondary">{{#str}}cancel{{/str}}</button>
         </div>
+        <div class="clearfix"></div>
     </form>
 </div>
index f756098..96afe15 100644 (file)
@@ -15,6 +15,8 @@
     along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 }}
 {{!
+    @template tool_lp/competency_path
+
     Competency path template.
 
     Classes required for JS:
     * framework - The competency framework
       * id - competency id
       * name - competency idnumber
-      * first - true if node is in first position
-      * last - true if node is in last position
-      * position - the position of the node in the list
 
     * ancestors - array of nodes
       * id - competency id
       * name - competency idnumber
       * first - true if node is in first position
       * last - true if node is in last position
-      * position - the position of the node in the list
 
     * pluginbaseurl - base url of plugin tool_lp
+
+    Example context (json):
+    {
+        "framework": {
+            "id": "1",
+            "name": "Framework"
+        },
+        "ancestors": [
+            {
+                "id": "1",
+                "name": "C1"
+            },
+            {
+                "id": "1",
+                "name": "C2",
+                "last": true
+            }
+        ]
+    }
 }}
 <nav id="competency-path-{{uniqid}}">
     <small>
index 916522b..f9693d0 100644 (file)
@@ -1,20 +1,75 @@
+{{!
+    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/>.
+}}
+{{!
+    @template tool_lp/competency_picker
+
+    Show a competency tree and allow picking a competency.
+
+    Context variables required for this template:
+    * frameworks - array of competency framework
+      * id
+      * shortname
+      * idnumber
+      * selected
+
+    * framework - competency framework
+      * id
+      * name
+      * shortname
+      * idnumber
+
+    * competencies - array of nodes
+      * id - competency id
+      * name - competency idnumber
+      * children - array of children
+      * haschildren - boolean
+
+    Example context (json):
+    {
+        "frameworks": [
+            {
+                "id": "1",
+                "shortname": "Framework",
+                "idnumber": "F1"
+            }
+        ],
+        "competencies": [
+        ]
+    }
+}}
 <div data-region="competencylinktree">
 {{^singleFramework}}
 <h3>{{#str}}competencyframeworks, tool_lp{{/str}}</h3>
-<select data-action="chooseframework">
+<select data-action="chooseframework" class="custom-select">
 {{#frameworks}}
 <option value="{{id}}" {{#selected}}selected="selected"{{/selected}}>{{{shortname}}} <em>{{idnumber}}</em></option>
 {{/frameworks}}
 </select>
 {{/singleFramework}}
-<h3>{{#str}}locatecompetency, tool_lp{{/str}}</h3>
+<h3 class="m-t-1">{{#str}}locatecompetency, tool_lp{{/str}}</h3>
 
-<form data-region="filtercompetencies" data-frameworkid="{{framework.id}}">
-    <label class="accesshide" for="filter{{uniqid}}">{{#str}}search, tool_lp{{/str}}</label>
-    <input type="text" id="filter{{uniqid}}" placeholder="{{#str}}search, tool_lp{{/str}}" value="{{search}}">
-    <button>{{#pix}}a/search, ,{{#str}}search{{/str}}{{/pix}}</button>
+<form data-region="filtercompetencies" class="form-inline" data-frameworkid="{{framework.id}}">
+    <div class="form-group">
+        <label class="accesshide" for="filter{{uniqid}}">{{#str}}search, tool_lp{{/str}}</label>
+        <input type="text" class="form-control" id="filter{{uniqid}}" placeholder="{{#str}}search, tool_lp{{/str}}" value="{{search}}">
+        <button class="btn btn-secondary">{{#pix}}a/search, ,{{#str}}search{{/str}}{{/pix}}</button>
+    </div>
 </form>
-<ul data-enhance="linktree" style="display: none;">
+<ul data-enhance="linktree" style="display: none;" class="m-t-1 competency-tree">
     <li><span>{{{framework.shortname}}}</span>
         <ul>
             {{#competencies}}
@@ -23,8 +78,9 @@
         </ul>
     </li>
 </ul>
-<div data-region="link-buttons">
-    <input type="button" data-action="add" value="{{#str}}add{{/str}}"/>
-    <input type="button" data-action="cancel" value="{{#str}}cancel{{/str}}"/>
+<div data-region="link-buttons" class="m-t-1 pull-xs-right">
+    <input type="button" class="btn btn-primary" data-action="add" value="{{#str}}add{{/str}}"/>
+    <input type="button" class="btn btn-secondary" data-action="cancel" value="{{#str}}cancel{{/str}}"/>
 </div>
+<div class="clearfix"></div>
 </div>
index e255dfd..08b38ef 100644 (file)
@@ -1,12 +1,57 @@
+{{!
+    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/>.
+}}
+{{!
+    @template tool_lp/competency_picker_competencyform
+
+    Show a competency tree and allow picking a competency.
+
+    Context variables required for this template:
+    * framework - The competency framework
+      * id
+      * name
+      * shortname
+
+    * competencies - array of nodes
+      * id - competency id
+      * name - competency idnumber
+      * children - array of children
+      * haschildren - boolean
+
+    Example context (json):
+    {
+        "framework": {
+            "id": "1",
+            "name": "Framework"
+        },
+        "competencies": [
+        ]
+    }
+}}
 <div data-region="competencylinktree">
 <h3>{{#str}}locatecompetency, tool_lp{{/str}}</h3>
 
-<form data-region="filtercompetencies" data-frameworkid="{{framework.id}}">
-    <label class="accesshide" for="filter{{uniqid}}">{{#str}}search, tool_lp{{/str}}</label>
-    <input type="text" id="filter{{uniqid}}" placeholder="{{#str}}search, tool_lp{{/str}}" value="{{search}}">
-    <button>{{#pix}}a/search, ,{{#str}}search{{/str}}{{/pix}}</button>
+<form data-region="filtercompetencies" class="form-inline" data-frameworkid="{{framework.id}}">
+    <div class="form-group">
+        <label class="accesshide" for="filter{{uniqid}}">{{#str}}search, tool_lp{{/str}}</label>
+        <input type="text" class="form-control" id="filter{{uniqid}}" placeholder="{{#str}}search, tool_lp{{/str}}" value="{{search}}">
+        <button class="btn btn-secondary">{{#pix}}a/search, ,{{#str}}search{{/str}}{{/pix}}</button>
+    </div>
 </form>
-<ul data-enhance="linktree" style="display: none;">
+<ul data-enhance="linktree" style="display: none;" class="m-t-1 competency-tree">
     <li data-id="0"><span>{{{framework.shortname}}}</span>
         <ul>
             {{#competencies}}
@@ -15,8 +60,9 @@
         </ul>
     </li>
 </ul>
-<div data-region="link-buttons">
-    <input type="button" data-action="add" value="{{#str}}select{{/str}}"/>
-    <input type="button" data-action="cancel" value="{{#str}}cancel{{/str}}"/>
+<div data-region="link-buttons" class="m-t-1 pull-xs-right">
+    <input type="button" class="btn btn-primary" data-action="add" value="{{#str}}select{{/str}}"/>
+    <input type="button" class="btn btn-secondary" data-action="cancel" value="{{#str}}cancel{{/str}}"/>
 </div>
+<div class="clearfix"></div>
 </div>
index bddebc9..7ee035d 100644 (file)
@@ -1,22 +1,80 @@
+{{!
+    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/>.
+}}
+{{!
+    @template tool_lp/competency_picker_user_plans
+
+    Show a competency tree and allow picking a competency.
+
+    Context variables required for this template:
+    * singlePlan - boolean
+
+    * plans - array of plans
+      * id
+      * selected
+      * name
+
+    * plan
+      * id
+      * name
+
+    * competencies - array of nodes
+      * id - competency id
+      * name - competency idnumber
+      * children - array of children
+      * haschildren - boolean
+
+    Example context (json):
+    {
+        "singlePlan": false,
+        "plans": [
+            {
+                "id": "1",
+                "name": "Plan"
+            }
+        ],
+        "plan": {
+            "id": "1",
+            "name": "Plan"
+        },
+        "competencies": []
+    }
+}}
+
 <div data-region="competencylinktree">
 {{^singlePlan}}
     <h3>{{#str}}learningplans, tool_lp{{/str}}</h3>
-    <select data-action="chooseplan">
+    <select data-action="chooseplan" class="custom-select">
     {{#plans}}
         <option value="{{id}}" {{#selected}}selected="selected"{{/selected}}>{{{name}}}</option>
     {{/plans}}
     </select>
 {{/singlePlan}}
 
-<h3>{{#str}}locatecompetency, tool_lp{{/str}}</h3>
+<h3 class="m-t-1">{{#str}}locatecompetency, tool_lp{{/str}}</h3>
 
-<form data-region="filtercompetencies" data-planid="{{plan.id}}">
-    <label class="accesshide" for="filter{{uniqid}}">{{#str}}search, tool_lp{{/str}}</label>
-    <input type="text" id="filter{{uniqid}}" placeholder="{{#str}}search, tool_lp{{/str}}" value="{{search}}">
-    <button>{{#pix}}a/search, ,{{#str}}search{{/str}}{{/pix}}</button>
+<form data-region="filtercompetencies" data-planid="{{plan.id}}" class="form-inline">
+    <div class="form-group">
+        <label class="accesshide" for="filter{{uniqid}}">{{#str}}search, tool_lp{{/str}}</label>
+        <input type="text" class="form-control" id="filter{{uniqid}}" placeholder="{{#str}}search, tool_lp{{/str}}" value="{{search}}">
+        <button class="btn btn-secondary">{{#pix}}a/search, ,{{#str}}search{{/str}}{{/pix}}</button>
+    </div>
 </form>
 
-<ul data-enhance="linktree" style="display: none;">
+<ul data-enhance="linktree" style="display: none;" class="m-t-1 competency-tree">
     <li><span>{{{plan.name}}}</span>
         <ul>
             {{#competencies}}
@@ -26,9 +84,9 @@
     </li>
 </ul>
 
-<div data-region="link-buttons">
-    <input type="button" data-action="add" value="{{#str}}add{{/str}}"/>
-    <input type="button" data-action="cancel" value="{{#str}}cancel{{/str}}"/>
+<div data-region="link-buttons" class="m-t-1 pull-xs-right">
+    <input type="button" class="btn btn-primary" data-action="add" value="{{#str}}add{{/str}}"/>
+    <input type="button" class="btn btn-secondary" data-action="cancel" value="{{#str}}cancel{{/str}}"/>
 </div>
-
+<div class="clearfix"></div>
 </div>
index d3eb766..21bd7af 100644 (file)
@@ -1,4 +1,38 @@
-<div class="pull-right well">
+{{!
+    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/>.
+}}
+{{!
+    @template tool_lp/competency_plan_navigation
+
+    Show an auto-complete for jumping to competencies in a plan.
+
+    Context variables required for this template:
+    * hascompetencies - boolean
+    * competencies - array of competencies
+      * id
+      * shortname
+      * idnumber
+      * selected
+    * userid
+    * competencyid
+    * planid
+
+    // No example context because the JS is connected to webservices
+}}
+<div class="pull-xs-right card card-block">
 {{#hascompetencies}}
 <span>
 <label for="competency-nav-{{uniqid}}" class="accesshide">{{#str}}jumptocompetency, tool_lp{{/str}}</label>
@@ -9,7 +43,6 @@
 </select>
 </span>
 {{/hascompetencies}}
-</form>
 </div>
 {{#js}}
 require(['core/form-autocomplete', 'tool_lp/competency_plan_navigation'], function(autocomplete, nav) {
index 7c64ab6..b0e9db8 100644 (file)
@@ -1,3 +1,54 @@
+{{!
+    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/>.
+}}
+{{!
+    @template tool_lp/competency_rule_config
+
+    Configuration dialogue for competency rules.
+
+    Context variables required for this template:
+    * config - boolean
+    * outcomes - array
+      * code
+      * name
+      * selected
+    * rules - array
+      * type
+      * name
+      * selected
+
+    Example context (json):
+    {
+        "config": true,
+        "outcomes": [
+            {
+                "code": "C1",
+                "name": "Complete",
+                "selected": true
+            }
+        ],
+        "rules": [
+            {
+                "type": "Type",
+                "name": "Something happens",
+                "selected": true
+            }
+        ]
+    }
+}}
 <div data-region="competencyruleconfig">
     <div data-region="content">
 
         {{/config}}
 
         {{#config}}
-        <div data-region="rule-base">
-            <div data-region="rule-outcome">
+        <div data-region="rule-base" class="form">
+            <div data-region="rule-outcome" class="form-group">
                 <label>{{#str}}outcome, tool_lp{{/str}}</label>
-                <select name="outcome" ng-label="{{#str}}outcome, tool_lp{{/str}}">
+                <select name="outcome" class="custom-select" ng-label="{{#str}}outcome, tool_lp{{/str}}">
                     {{#outcomes}}
                     <option value="{{code}}" {{#selected}}selected{{/selected}}>{{name}}</option>
                     {{/outcomes}}
                 </select>
             </div>
-            <div data-region="rule-type">
+            <div data-region="rule-type" class="form-group">
                 <label>{{#str}}when, tool_lp{{/str}}</label>
-                <select name="rule" ng-label="{{#str}}when, tool_lp{{/str}}">
+                <select name="rule" class="custom-select" ng-label="{{#str}}when, tool_lp{{/str}}">
                     <option value="-1">{{#str}}choosedots{{/str}}</option>
                     {{#rules}}
                     <option value="{{type}}" {{#selected}}selected{{/selected}}>{{name}}</option>
         {{/config}}
     </div>
 
-    <div data-region="footer">
+    <div data-region="footer" class="pull-xs-right">
         {{#config}}
-        <input type="button" data-action="save" value="{{#str}}savechanges{{/str}}"/>
+        <input type="button" class="btn btn-primary" data-action="save" value="{{#str}}savechanges{{/str}}"/>
         {{/config}}
-        <input type="button" data-action="cancel" value="{{#str}}cancel{{/str}}"/>
+        <input type="button" class="btn btn-secondary" data-action="cancel" value="{{#str}}cancel{{/str}}"/>
     </div>
 </div>
index 907e731..07e4392 100644 (file)
@@ -1,3 +1,43 @@
+{{!
+    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/>.
+}}
+{{!
+    @template tool_lp/competency_rule_points
+
+    Configuration dialogue for competency points rule.
+
+    Context variables required for this template:
+    * children
+      * id
+      * shortname
+      * points
+    * requiredpoints
+
+    Example context (json):
+    {
+        "children": [
+            {
+                "id": "1",
+                "shortname": "Competency",
+                "points": 2
+            }
+        ],
+        "requiredpoints": 4
+    }
+}}
 <div class="competency-rule-points">
     <table class="table table-condensed">
         <thead>
@@ -13,7 +53,7 @@
                 <th scope="row">{{{shortname}}}</th>
                 <td>
                     <label class="accesshide" for="pointsforcompetency-{{id}}">{{#str}}pointsgivenfor, tool_lp, {{{competency.shortname}}}{{/str}}</label>
-                    <input id="pointsforcompetency-{{id}}" type="number" min="0" value="{{points}}" name="points" />
+                    <input id="pointsforcompetency-{{id}}" type="number" min="0" value="{{points}}" name="points" class="form-control"/>
                 </td>
                 <td>
                     <label class="accesshide" for="competency-{{id}}-isrequired">{{#str}}aisrequired, tool_lp, {{{competency.shortname}}}{{/str}}</label>
@@ -25,7 +65,7 @@
         <tfoot>
             <tr>
                 <th scope="row">{{#str}}totalrequiredtocomplete, tool_lp{{/str}}</th>
-                <td><input type="number" min="1" value="{{requiredpoints}}" name="requiredpoints" aria-label="{{#str}}totalrequiredtocomplete, tool_lp{{/str}}"></td>
+                <td><input type="number" min="1" value="{{requiredpoints}}" name="requiredpoints" aria-label="{{#str}}totalrequiredtocomplete, tool_lp{{/str}}" class="form-control"></td>
                 <td> </td>
             </tr>
         </tfoot>
index b1bca28..1ce22b1 100644 (file)
@@ -1,3 +1,53 @@
+{{!
+    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/>.
+}}
+{{!
+    @template tool_lp/competency_summary
+
+    Summary of a competency
+
+    Context variables required for this template:
+    * competency
+      * id
+      * shortname
+      * idnumber
+      * description
+    * framework
+      * shortname
+    * comppath array of ancestors
+    * showrelatedcompetencies boolean
+    * related
+    * showrule boolean
+    * rule
+      * outcome
+      * type
+
+    Example context (json):
+    {
+        "competency": {
+            "id": 1,
+            "shortname": "C1",
+            "idnumber": "PATH",
+            "description": "Can do something"
+        },
+        "framework": {
+            "shortname": "F1"
+        }
+    }
+}}
 <div class='competency-heading'>
     <h4 id="competency_link_{{competency.id}}">{{{competency.shortname}}}
         <small>{{competency.idnumber}}</small>
index 674eed6..39b061e 100644 (file)
 }}
 {{!
     Course competencies template.
+
+    For a full list of the context for this template see the course_competencies_page renderable.
 }}
 <div data-region="coursecompetenciespage">
     <div data-region="actions" class="clearfix">
-        <div class="pull-left">
+        <div class="pull-xs-left">
             {{#canmanagecoursecompetencies}}
-                <button disabled>{{#str}}addcoursecompetencies, tool_lp{{/str}}</button>
+                <button class="btn btn-secondary" disabled>{{#str}}addcoursecompetencies, tool_lp{{/str}}</button>
             {{/canmanagecoursecompetencies}}
         </div>
     </div>
     <tr class="drag-samenode" data-id="{{competency.id}}">
     <td>
         {{#canmanagecoursecompetencies}}
-        <span class="drag-handlecontainer pull-left"></span>
-        <div class="pull-right">
+        <span class="drag-handlecontainer pull-xs-left"></span>
+        <div class="pull-xs-right">
             <a href="#" data-action="delete-competency-link" data-id="{{competency.id}}">
                 {{#pix}}t/delete, core, {{#str}}delete{{/str}}{{/pix}}
             </a>
         </div>
+        <div class="clearfix"></div>
         {{/canmanagecoursecompetencies}}
         {{#competency}}
             <a href="{{pluginbaseurl}}user_competency_in_course.php?courseid={{courseid}}&competencyid={{competency.id}}&userid={{gradableuserid}}"
@@ -71,7 +74,7 @@
             <p>{{{competency.description}}}</p>
         {{/competency}}
         {{#comppath}}
-            <span class="pull-left">{{#str}}path, tool_lp{{/str}}&nbsp;</span>{{> tool_lp/competency_path }}
+            <span class="pull-xs-left">{{#str}}path, tool_lp{{/str}}&nbsp;</span>{{> tool_lp/competency_path }}
         {{/comppath}}
         {{#usercompetencycourse}}
             {{#grade}}
         {{/canmanagecoursecompetencies}}
         <div data-region="coursecompetencyactivities">
         <p>
-        <ul class="inline">
+        <ul class="inline list-inline">
         {{#coursemodules}}
-            <li><a href="{{url}}"><img src="{{iconurl}}"> {{name}} </a></li>
+            <li class="list-inline-item"><a href="{{url}}"><img src="{{iconurl}}"> {{name}} </a></li>
         {{/coursemodules}}
         {{^coursemodules}}
-            <li><span class="alert">{{#str}}noactivities, tool_lp{{/str}}</span></li>
+            <li class="list-inline-item"><span class="alert">{{#str}}noactivities, tool_lp{{/str}}</span></li>
         {{/coursemodules}}
         </ul>
         </p>
index bc1e361..6992f7d 100644 (file)
@@ -1,3 +1,40 @@
+{{!
+    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/>.
+}}
+{{!
+    @template tool_lp/course_competency_settings
+
+    Select an action to execute.
+
+    Classes required for JS:
+    * none
+
+    Data attibutes required for JS:
+    * none
+
+    Context variables required for this template:
+    * courseid
+    * pushratingstouserplans
+
+    Example context (json):
+    {
+        "pushratingstouserplans": false,
+        "courseid": -1
+    }
+}}
 <form data-region="coursecompetencysettings">
     <input type="hidden" name="courseid" value="{{courseid}}"/>
     <fieldset>
         </label>
 
     </fieldset>
-    <fieldset>
-        <center>
-        <input type="button" data-action="save" value="{{#str}}savechanges{{/str}}"/>
-        <input type="button" data-action="cancel" value="{{#str}}cancel{{/str}}"/>
-        </center>
+    <fieldset class="pull-xs-right">
+        <input type="button" class="btn btn-primary" data-action="save" value="{{#str}}savechanges{{/str}}"/>
+        <input type="button" class="btn btn-secondary" data-action="cancel" value="{{#str}}cancel{{/str}}"/>
     </fieldset>
+    <div class="clearfix"></div>
 </form>
index bb4a267..9891b57 100644 (file)
     Example context (json):
     {
         "competencycount": 4,
+        "canbegradedincourse": true,
+        "canmanagecoursecompetencies": true,
         "proficientcompetencycount": 3,
         "proficientcompetencypercentage": 75,
-        "proficientcompetencypercentageformatted": 75.0
+        "proficientcompetencypercentageformatted": 75.0,
+        "leastproficientcount": 1,
+        "leastproficient": [
+            { "id": 1, "shortname": "Comp 1", "idnumber": "C1" }
+        ]
     }
 
 }}
index 64f1bc6..128fd9c 100644 (file)
@@ -46,7 +46,7 @@
 }}
 <div class="well well-small evidence" data-region="evidence" data-id="{{id}}">
     {{#candelete}}
-        <div class="pull-right">
+        <div class="pull-xs-right">
             <a href="#" data-action="delete-evidence">{{#pix}}t/delete{{/pix}}</a>
         </div>
     {{/candelete}}
@@ -57,7 +57,7 @@
 {{/actionuser}}
 <strong><time datetime="{{userdate}}">{{userdate}}</time></strong>
 {{#grade}}
-    <p><span class="label">{{gradename}}</span></p>
+    <p><span class="tag tag-info">{{gradename}}</span></p>
 {{/grade}}
 <p>{{description}}</p>
 {{#note}}
index 7208304..2e65cdb 100644 (file)
@@ -1,3 +1,48 @@
+{{!
+    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/>.
+}}
+{{!
+    @template tool_lp/linked_courses_summary
+
+    Moodle template for the list of linked courses to a competency
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Context variables required for this template:
+    * courses array
+      * viewurl
+      * fullname
+      * shortname
+
+    Example context (json):
+    { "courses":
+        [
+            {
+                "viewurl": "http://example.com",
+                "fullname": "Course 1",
+                "shortname": "C1"
+            }
+        ]
+    }
+}}
+
 <p>
 {{#str}}coursesusingthiscompetency, tool_lp{{/str}}
 </p>
index fce2b3d..8349d31 100644 (file)
     {{/canmanage}}
 </h2>
 <div>{{{framework.description}}}</div>
-<h3>{{#str}}competencies, core_competency{{/str}}</h3>
-<div class="row-fluid">
-<div class="span6">
-<p>
-<form data-region="filtercompetencies" data-frameworkid="{{framework.id}}">
-    <label class="accesshide" for="filter{{uniqid}}">{{#str}}search, tool_lp{{/str}}</label>
-    <input type="text" id="filter{{uniqid}}" placeholder="{{#str}}search, tool_lp{{/str}}" value="{{search}}">
-    <button>{{#pix}}a/search, , {{#str}}search{{/str}}{{/pix}}</button>
-</form>
-</p>
-<ul data-enhance="tree">
-    {{> tool_lp/loading }}
-</ul>
-</div>
-
-<div class="span6 well">
-<h4 data-region="selected-competency">{{#str}}selectedcompetency, tool_lp{{/str}}</h4>
-<p data-region="competencyinfo">
-{{#str}}nocompetencyselected, tool_lp{{/str}}
-</p>
-{{#canmanage}}
-<div data-region="competencyactions">
-<button class="btn" data-action="add">{{#pix}}t/add{{/pix}} <span data-region="term"></span></button>
-            <span data-region="competencyactionsmenu">
-            <ul title="{{#str}}edit{{/str}}" class="competencyactionsmenu">
-                <li>
-                    <a href="#">{{#str}}edit{{/str}}</a><b class="caret"></b>
-                    <ul class="dropdown-menu">
-                        <li>
-                            <a href="#" data-action="edit">
-                                {{#pix}}t/edit{{/pix}} {{#str}}edit{{/str}}
-                            </a>
-                        </li>
-                        <li>
-                            <a href="#" data-action="move">
-                                {{#pix}}t/move{{/pix}} {{#str}}movetonewparent, tool_lp{{/str}}
-                            </a>
-                        </li>
-                        <li>
-                            <a href="#" data-action="delete">
-                                {{#pix}}t/delete{{/pix}} {{#str}}delete{{/str}}
-                            </a>
-                        </li>
-                        <li>
-                            <a href="#" data-action="moveup">
-                                {{#pix}}t/up{{/pix}} {{#str}}moveup{{/str}}
-                            </a>
-                        </li>
-                        <li>
-                            <a href="#" data-action="movedown">
-                                {{#pix}}t/down{{/pix}} {{#str}}movedown{{/str}}
-                            </a>
-                        </li>
-                        <li>
-                            <a href="#" data-action="linkedcourses">
-                                {{#pix}}t/viewdetails{{/pix}} {{#str}}linkedcourses, tool_lp{{/str}}
-                            </a>
-                        </li>
-                        <li>
-                            <a href="#" data-action="relatedcompetencies">
-                                {{#pix}}t/add{{/pix}} {{#str}}addcrossreferencedcompetency, tool_lp{{/str}}
-                            </a>
-                        </li>
-                        <li>
-                            <a href="#" data-action="competencyrules">
-                                {{#pix}}t/edit{{/pix}} {{#str}}competencyrule, tool_lp{{/str}}
-                            </a>
-                        </li>
-                    </ul>
-                </li>
+    <h3>{{#str}}competencies, core_competency{{/str}}</h3>
+    <div class="row-fluid">
+        <div class="span6 col-lg-6">
+            <p>
+                <form data-region="filtercompetencies" data-frameworkid="{{framework.id}}" class="form-inline">
+                    <div class="form-group">
+                        <label class="accesshide" for="filter{{uniqid}}">{{#str}}search, tool_lp{{/str}}</label>
+                        <input class="form-control" type="text" id="filter{{uniqid}}" placeholder="{{#str}}search, tool_lp{{/str}}" value="{{search}}">
+                        <button class="btn btn-secondary">{{#pix}}a/search, , {{#str}}search{{/str}}{{/pix}}</button>
+                    </div>
+                </form>
+            </p>
+            <ul data-enhance="tree" class="competency-tree">
+                {{> tool_lp/loading }}
             </ul>
-            </span>
-</div>
-</div>
-{{/canmanage}}
+        </div>
+
+        <div class="span6 card col-lg-6">
+            <div class="card-block">
+                <div class="card-title">
+                    <h4 data-region="selected-competency">{{#str}}selectedcompetency, tool_lp{{/str}}</h4>
+                        <span data-region="competencyactionsmenu" class="pull-xs-right">
+                            <ul title="{{#str}}edit{{/str}}" class="competencyactionsmenu">
+                                <li>
+                                    <a href="#">{{#str}}edit{{/str}}</a><b class="caret"></b>
+                                    <ul class="dropdown-menu">
+                                    <li class="dropdown-item">
+                                        <a href="#" data-action="edit">
+                                            {{#pix}}t/edit{{/pix}} {{#str}}edit{{/str}}
+                                        </a>
+                                    </li>
+                                    <li class="dropdown-item">
+                                        <a href="#" data-action="move">
+                                            {{#pix}}t/move{{/pix}} {{#str}}movetonewparent, tool_lp{{/str}}
+                                        </a>
+                                    </li>
+                                    <li class="dropdown-item">
+                                        <a href="#" data-action="delete">
+                                            {{#pix}}t/delete{{/pix}} {{#str}}delete{{/str}}
+                                        </a>
+                                    </li>
+                                    <li class="dropdown-item">
+                                        <a href="#" data-action="moveup">
+                                            {{#pix}}t/up{{/pix}} {{#str}}moveup{{/str}}
+                                        </a>
+                                    </li>
+                                    <li class="dropdown-item">
+                                        <a href="#" data-action="movedown">
+                                            {{#pix}}t/down{{/pix}} {{#str}}movedown{{/str}}
+                                        </a>
+                                    </li>
+                                    <li class="dropdown-item">
+                                        <a href="#" data-action="linkedcourses">
+                                            {{#pix}}t/viewdetails{{/pix}} {{#str}}linkedcourses, tool_lp{{/str}}
+                                        </a>
+                                    </li>
+                                    <li class="dropdown-item">
+                                        <a href="#" data-action="relatedcompetencies">
+                                            {{#pix}}t/add{{/pix}} {{#str}}addcrossreferencedcompetency, tool_lp{{/str}}
+                                        </a>
+                                    </li>
+                                    <li class="dropdown-item">
+                                        <a href="#" data-action="competencyrules">
+                                            {{#pix}}t/edit{{/pix}} {{#str}}competencyrule, tool_lp{{/str}}
+                                        </a>
+                                    </li>
+                                </ul>
+                            </li>
+                        </ul>
+                    </span>
+                </div>
+                <p data-region="competencyinfo">
+                    {{#str}}nocompetencyselected, tool_lp{{/str}}
+                </p>
+                {{#canmanage}}
+                <div data-region="competencyactions">
+                    <button class="btn btn-secondary" data-action="add">{{#pix}}t/add{{/pix}} <span data-region="term"></span></button>
+                </div>
+                {{/canmanage}}
+            </div>
+        </div>
+    </div>
 </div>
 
 {{#js}}
@@ -131,4 +138,3 @@ require(['tool_lp/tree', 'tool_lp/competencytree', 'tool_lp/competencyactions',
 });
 {{/js}}
 
-</div>
index a901f4a..f3d6a3e 100644 (file)
                 <li>
                     <a href="#">{{#str}}edit{{/str}}</a><b class="caret"></b>
                     <ul class="dropdown-menu">
-                        <li>
+                        <li class="dropdown-item">
                             <a href="{{pluginbaseurl}}/editcompetencyframework.php?id={{id}}&amp;pagecontextid={{pagecontextid}}">
                                 {{#pix}}t/edit{{/pix}} {{#str}}edit{{/str}}
                             </a>
                         </li>
-                        <li>
+                        <li class="dropdown-item">
                             <a data-action="duplicatecompetencyframework" href="#" data-frameworkid="{{id}}">
                                 {{#pix}}t/copy{{/pix}} {{#str}}duplicate{{/str}}
                             </a>
                         </li>
-                        <li>
+                        <li class="dropdown-item">
                             <a data-action="deletecompetencyframework" href="#" data-frameworkid="{{id}}">
                                 {{#pix}}t/delete{{/pix}} {{#str}}delete{{/str}}
                             </a>
index fbe00d6..f0af972 100644 (file)
                 <li>
                     <a href="#">{{#str}}edit{{/str}}</a><b class="caret"></b>
                     <ul class="dropdown-menu">
-                        <li>
+                        <li class="dropdown-item">
                             <a href="{{pluginbaseurl}}/edittemplate.php?id={{id}}&amp;pagecontextid={{pagecontextid}}&amp;return=templates">
                                 {{#pix}}t/edit{{/pix}} {{#str}}edit{{/str}}
                             </a>
                         </li>
-                        <li>
+                        <li class="dropdown-item">
                             <a data-action="duplicatetemplate" data-templateid="{{id}}" href="#">
                                 {{#pix}}t/copy{{/pix}} {{#str}}duplicate{{/str}}
                             </a>
                         </li>
-                        <li>
+                        <li class="dropdown-item">
                             <a href="{{pluginbaseurl}}/template_plans.php?id={{id}}&amp;pagecontextid={{pagecontextid}}">
                                 {{#pix}}t/add{{/pix}} {{#str}}createlearningplans, tool_lp{{/str}}
                             </a>
                         </li>
-                        <li>
+                        <li class="dropdown-item">
                             <a href="{{pluginbaseurl}}/template_cohorts.php?id={{id}}&amp;pagecontextid={{pagecontextid}}">
                                 {{#pix}}t/add{{/pix}} {{#str}}addcohortstosync, tool_lp{{/str}}
                             </a>
                         </li>
-                        <li>
+                        <li class="dropdown-item">
                             <a data-action="deletetemplate" data-templateid="{{id}}" href="#">
                                 {{#pix}}t/delete{{/pix}} {{#str}}delete{{/str}}
                             </a>
index 40eced3..a606c48 100644 (file)
@@ -1,3 +1,33 @@
-<p class="alert alert-error">
+{{!
+    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/>.
+}}
+{{!
+    @template tool_lp/no_frameworks_warning
+
+    No frameworks warning template.
+
+    Classes required for JS:
+      None
+
+    Context variables required for this template:
+      None
+    Example context (json):
+    {
+    }
+}}
+<p class="alert alert-danger">
     {{#str}}nocompetencyframeworks, tool_lp{{/str}}
 </p>
index 20eb2bb..d927eae 100644 (file)
     <div data-region="actions" class="clearfix">
         <div class="pull-left">
             <!-- Button to add competencies to the plan -->
-            <button class="btn" data-action="add">{{#pix}}t/add{{/pix}} {{#str}}addcompetency, tool_lp{{/str}}</button>
+            <button class="btn btn-secondary" data-action="add">{{#pix}}t/add{{/pix}} {{#str}}addcompetency, tool_lp{{/str}}</button>
         </div>
     </div>
     {{/plan.canbeedited}}
-    <div data-region="plan-summary">
+    <div data-region="plan-summary" class="m-t-1">
         {{{plan.description}}}
         <dl>
             <dt>{{#str}}status, tool_lp{{/str}}</dt>
     </div>
     {{#plan.commentarea}}
         {{#canpostorhascomments}}
-            <div data-region="comments">
+            <div data-region="comments" class="m-t-1">
                 {{>tool_lp/comment_area}}
             </div>
         {{/canpostorhascomments}}
     {{/plan.commentarea}}
-    <div data-region="plan-competencies">
+    <div data-region="plan-competencies" class="m-t-1">
         <h3>{{#str}}learningplancompetencies, tool_lp{{/str}}</h3>
         <table class="generaltable fullwidth managecompetencies">
             <thead>
                                     <a href="#">{{#str}}edit{{/str}}</a><b class="caret"></b>
                                     <ul class="dropdown-menu">
                                         {{#usercompetency.isrequestreviewallowed}}
-                                            <li>
+                                            <li class="dropdown-item">
                                                 <a href="#" data-action="request-review">{{#pix}}t/edit, core{{/pix}} {{#str}}requestreview, tool_lp{{/str}}</a>
                                             </li>
                                         {{/usercompetency.isrequestreviewallowed}}
                                         {{#usercompetency.iscancelreviewrequestallowed}}
-                                            <li>
+                                            <li class="dropdown-item">
                                                 <a href="#" data-action="cancel-review-request">{{#pix}}t/edit, core{{/pix}} {{#str}}cancelreviewrequest, tool_lp{{/str}}</a>
                                             </li>
                                         {{/usercompetency.iscancelreviewrequestallowed}}
                                         {{#plan.canbeedited}}
-                                            <li>
+                                            <li class="dropdown-item">
                                                 <a href="#" data-action="delete-competency-link" data-id="{{competency.id}}">{{#pix}}t/delete, core{{/pix}} {{#str}}delete{{/str}}</a>
                                             </li>
                                         {{/plan.canbeedited}}
-                                        <li>
+                                        <li class="dropdown-item">
                                             <a href="#" data-action="find-courses-link" data-id="{{competency.id}}">{{#pix}}t/preview, core{{/pix}} {{#str}}findcourses, tool_lp{{/str}}</a>
                                         </li>
                                     </ul>
index 94226c9..84a4b66 100644 (file)
@@ -71,7 +71,7 @@
                 <li>
                     <a href="#">{{#str}}edit{{/str}}</a><b class="caret"></b>
                     <ul class="dropdown-menu">
-                    <li {{^canbeedited}} class="disabled" {{/canbeedited}}>
+                    <li class="{{^canbeedited}} disabled {{/canbeedited}} dropdown-item">
                         <a href="{{#canbeedited}}
                                     {{pluginbaseurl}}/editplan.php?id={{id}}&amp;userid={{userid}}&amp;return=plans
                                  {{/canbeedited}}
                         </a>
                     </li>
                     {{#isreopenallowed}}
-                    <li>
+                    <li class="dropdown-item">
                         <a data-action="plan-reopen" href="#">
                             {{#pix}}t/edit{{/pix}} {{#str}}reopenplan, tool_lp{{/str}}
                         </a>
                     </li>
                     {{/isreopenallowed}}
                     {{#iscompleteallowed}}
-                    <li>
+                    <li class="dropdown-item">
                         <a data-action="plan-complete" href="#">
                             {{#pix}}t/edit{{/pix}} {{#str}}completeplan, tool_lp{{/str}}
                         </a>
                     </li>
                     {{/iscompleteallowed}}
                     {{#isrequestreviewallowed}}
-                    <li>
+                    <li class="dropdown-item">
                         <a data-action="plan-request-review" href="#">{{#pix}}t/edit{{/pix}} {{#str}}requestreview, tool_lp{{/str}}</a>
                     </li>
                     {{/isrequestreviewallowed}}
                     {{#iscancelreviewrequestallowed}}
-                    <li>
+                    <li class="dropdown-item">
                         <a data-action="plan-cancel-review-request" href="#">{{#pix}}t/edit{{/pix}} {{#str}}cancelreviewrequest, tool_lp{{/str}}</a>
                     </li>
                     {{/iscancelreviewrequestallowed}}
                     {{#isstartreviewallowed}}
-                    <li>
+                    <li class="dropdown-item">
                         <a data-action="plan-start-review" href="#">{{#pix}}t/edit{{/pix}} {{#str}}startreview, tool_lp{{/str}}</a>
                     </li>
                     {{/isstartreviewallowed}}
                     {{#isstopreviewallowed}}
-                    <li>
+                    <li class="dropdown-item">
                         <a data-action="plan-stop-review" href="#">{{#pix}}t/edit{{/pix}} {{#str}}stopreview, tool_lp{{/str}}</a>
                     </li>
                     {{/isstopreviewallowed}}
                     {{#isapproveallowed}}
-                    <li>
+                    <li class="dropdown-item">
                         <a data-action="plan-approve" href="#">{{#pix}}t/edit{{/pix}} {{#str}}planapprove, tool_lp{{/str}}</a>
                     </li>
                     {{/isapproveallowed}}
                     {{#isunapproveallowed}}
-                    <li>
+                    <li class="dropdown-item">
                         <a data-action="plan-unapprove" href="#">{{#pix}}t/edit{{/pix}} {{#str}}planunapprove, tool_lp{{/str}}</a>
                     </li>
                     {{/isunapproveallowed}}
                     {{#isunlinkallowed}}
-                    <li>
+                    <li class="dropdown-item">
                         <a data-action="plan-unlink" href="#">
                             {{#pix}}t/edit{{/pix}} {{#str}}unlinkplantemplate, tool_lp{{/str}}
                         </a>
                     </li>
                     {{/isunlinkallowed}}
-                    <li>
+                    <li class="dropdown-item">
                         <a data-action="plan-delete" href="#">
                             {{#pix}}t/delete{{/pix}} {{#str}}deletethisplan, tool_lp{{/str}}
                         </a>
 {{#js}}
 // Initialise the JS.
 require(['tool_lp/planactions'],
-        function(actionsMod) {
+        function(ActionsMod) {
 
-    var planActions = new actionsMod('plans');
+    var planActions = new ActionsMod('plans');
     planActions.enhanceMenubar('.planactions');
 });
 
index 71967d7..ab5d991 100644 (file)
@@ -1,3 +1,51 @@
+{{!
+    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/>.
+}}
+{{!
+    @template tool_lp/related_competencies
+
+    List of related competencies.
+
+    Classes required for JS:
+    * none
+
+    Data attributes required for JS:
+    * none
+
+    Context variables required for this template:
+    * showdeleterelatedaction boolean
+    * relatedcompetencies array
+      * id int
+      * shortname string
+      * idnumber string
+
+    Example context (json):
+    {
+        "showdeleterelatedaction": false,
+        "relatedcompetencies":
+        [
+            {
+                "id": 1,
+                "shortname": "Competency",
+                "idnumber": "C1"
+            }
+        ]
+    }
+
+}}
 <div data-region="relatedcompetencies">
 <p>
     <strong>{{#str}}crossreferencedcompetencies, tool_lp{{/str}}:</strong>
@@ -6,7 +54,7 @@
     {{#relatedcompetencies}}
         <li>
             {{#showdeleterelatedaction}}
-                <div class="pull-right">
+                <div class="pull-xs-right">
                     <a href="#" data-action="deleterelation" id="id-related-{{id}}">{{#pix}}t/delete, core, {{#str}}delete{{/str}}{{/pix}}</a>
                 </div>
             {{/showdeleterelatedaction}}
index 6b98119..3412c2e 100644 (file)
@@ -15,6 +15,8 @@
     along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 }}
 {{!
+    @template tool_lp/scale_configuration_page
+
     Set scale configuration for the competency framework.
 
     Classes required for JS:
@@ -30,7 +32,7 @@
     {
         "scales": [
             { "id": 1, "name": "Competent" },
-            { "id": 2, "name": "Not competent"}
+            { "id": 2, "name": "Not competent" }
         ]
     }
  }}
@@ -56,7 +58,8 @@
 </table>
 </div>
 
-<div data-region="scale-buttons">
-    <input type="button" data-action="close" value="{{#str}}closebuttontitle{{/str}}"/>
-    <input type="button" data-action="cancel" value="{{#str}}cancel{{/str}}"/>
-</div>
\ No newline at end of file
+<div data-region="scale-buttons" class="m-t-1 pull-xs-right">
+    <input type="button" class="btn btn-secondary" data-action="close" value="{{#str}}closebuttontitle{{/str}}"/>
+    <input type="button" class="btn btn-secondary" data-action="cancel" value="{{#str}}cancel{{/str}}"/>
+</div>
+<div class="clearfix"></div>
index a2ebaef..a380d29 100644 (file)
     {{#canmanagetemplatecompetencies}}
     <div data-region="actions" class="clearfix">
         <div class="pull-left">
-            <button disabled>{{#str}}addtemplatecompetencies, tool_lp{{/str}}</button>
+            <button disabled class="btn btn-secondary">{{#str}}addtemplatecompetencies, tool_lp{{/str}}</button>
         </div>
     </div>
     {{/canmanagetemplatecompetencies}}
-    <h3>{{#str}}templatecompetencies, tool_lp{{/str}}</h3>
+    <h3 class="m-t-1">{{#str}}templatecompetencies, tool_lp{{/str}}</h3>
     {{#statistics}}
         {{> tool_lp/template_statistics }}
     {{/statistics}}
@@ -44,7 +44,7 @@
                     <div class="well">
                         {{#canmanagetemplatecompetencies}}
                         <span class="drag-handlecontainer pull-left"></span>
-                        <div class="pull-right">
+                        <div class="pull-xs-right">
                             <a href="#" data-action="delete-competency-link" data-id="{{competency.id}}">{{#pix}}t/delete, core, {{#str}}delete{{/str}}{{/pix}}</a>
                         </div>
                         {{/canmanagetemplatecompetencies}}
@@ -53,9 +53,9 @@
                         {{/competency}}
                         <strong>{{#str}}linkedcourseslist, tool_lp{{/str}}</strong>
                         {{#hascourses}}
-                        <ul class="inline">
+                        <ul class="inline list-inline">
                         {{#linkedcourses}}
-                            <li><a href="{{viewurl}}?id={{id}}">{{{fullname}}} ({{{shortname}}})</a></li>
+                            <li class="list-inline-item"><a href="{{viewurl}}?id={{id}}">{{{fullname}}} ({{{shortname}}})</a></li>
                         {{/linkedcourses}}
                         </ul>
                         {{/hascourses}}
index 85b738f..9751cbd 100644 (file)
@@ -45,7 +45,8 @@
     Template statistics template.
 }}
 {{#competencycount}}
-<div data-region="templatestatistics" class="well">
+<div data-region="templatestatistics" class="card">
+    <div class="card-block">
     {{< tool_lp/progress_bar}}
         {{$progresstext}}
             {{#str}}xcompetencieslinkedoutofy, tool_lp, { "x": "{{linkedcompetencycount}}", "y": "{{competencycount}}" } {{/str}}
@@ -89,5 +90,6 @@
         </div>
     </div>
     {{/leastproficientcount}}
+    </div>
 </div>
 {{/competencycount}}
index a81c0f8..533d01f 100644 (file)
@@ -1,4 +1,41 @@
-<div class="pull-right well">
+{{!
+    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/>.
+}}
+{{!
+    @template tool_lp/user_competency_course_navigation
+
+    Show an auto-complete for jumping to competencies in a plan.
+
+    Context variables required for this template:
+    * groupselector - HTML
+    * hasusers
+    * users - array
+      * id
+      * selected
+      * fullname
+    * hascompetencies
+    * competencies - array
+      * id
+      * selected
+      * shortname
+      * idnumber
+
+    // No example context because the JS is connected to webservices
+}}
+<div class="pull-xs-right card card-block">
 <p>{{{groupselector}}}</p>
 <form class="user-competency-course-navigation">
 {{#hasusers}}
index 9097caa..0e280f6 100644 (file)
                 - {{reviewer.fullname}}
             {{/isstatusinreview}}
 
-            {{#isrequestreviewallowed}}<button data-action="request-review">{{#str}}requestreview, tool_lp{{/str}}</button>{{/isrequestreviewallowed}}
-            {{#iscancelreviewrequestallowed}}<button data-action="cancel-review-request">{{#str}}cancelreviewrequest, tool_lp{{/str}}</button>{{/iscancelreviewrequestallowed}}
-            {{#isstartreviewallowed}}<button data-action="start-review">{{#str}}startreview, tool_lp{{/str}}</button>{{/isstartreviewallowed}}
-            {{#isstopreviewallowed}}<button data-action="stop-review">{{#str}}stopreview, tool_lp{{/str}}</button>{{/isstopreviewallowed}}
+            {{#isrequestreviewallowed}}<button class="btn btn-secondary" data-action="request-review">{{#str}}requestreview, tool_lp{{/str}}</button>{{/isrequestreviewallowed}}
+            {{#iscancelreviewrequestallowed}}<button class="btn btn-secondary" data-action="cancel-review-request">{{#str}}cancelreviewrequest, tool_lp{{/str}}</button>{{/iscancelreviewrequestallowed}}
+            {{#isstartreviewallowed}}<button class="btn btn-secondary" data-action="start-review">{{#str}}startreview, tool_lp{{/str}}</button>{{/isstartreviewallowed}}
+            {{#isstopreviewallowed}}<button class="btn btn-secondary" data-action="stop-review">{{#str}}stopreview, tool_lp{{/str}}</button>{{/isstopreviewallowed}}
         </dd>
         <dt>{{#str}}proficient, tool_lp{{/str}}</dt>
         <dd>
@@ -64,7 +64,7 @@
         <dt>{{#str}}rating, tool_lp{{/str}}</dt>
         <dd>{{gradename}}
             {{#cangrade}}
-                <button class="btn" id="rate_{{uniqid}}">{{#str}}rate, tool_lp{{/str}}</button>
+                <button class="btn btn-secondary" id="rate_{{uniqid}}">{{#str}}rate, tool_lp{{/str}}</button>
             {{/cangrade}}
         </dd>
         {{#js}}
index 3a30f76..22cf96d 100644 (file)
         <dt>{{#str}}activities, tool_lp{{/str}}</dt>
         <dd data-region="coursecompetencyactivities">
         <p>
-        <ul class="inline">
+        <ul class="inline list-inline">
         {{#coursemodules}}
-            <li><a href="{{url}}"><img src="{{iconurl}}"> {{name}} </a></li>
+            <li class="list-inline-item"><a href="{{url}}"><img src="{{iconurl}}"> {{name}} </a></li>
         {{/coursemodules}}
         {{^coursemodules}}
-            <li><span class="alert">{{#str}}noactivities, tool_lp{{/str}}</span></li>
+            <li class="list-inline-item"><span class="alert">{{#str}}noactivities, tool_lp{{/str}}</span></li>
         {{/coursemodules}}
         </ul>
         </p>
@@ -75,7 +75,7 @@
         <dt>{{#str}}rating, tool_lp{{/str}}</dt>
         <dd>{{gradename}}
             {{#cangrade}}
-                <button class="btn" id="rate_{{uniqid}}">{{#str}}rate, tool_lp{{/str}}</button>
+                <button class="btn btn-secondary" id="rate_{{uniqid}}">{{#str}}rate, tool_lp{{/str}}</button>
             {{/cangrade}}
         </dd>
         {{/usercompetencycourse}}
index 7c81ad2..7253af1 100644 (file)
                 - {{reviewer.fullname}}
             {{/isstatusinreview}}
 
-            {{#isrequestreviewallowed}}<button data-action="request-review">{{#str}}requestreview, tool_lp{{/str}}</button>{{/isrequestreviewallowed}}
-            {{#iscancelreviewrequestallowed}}<button data-action="cancel-review-request">{{#str}}cancelreviewrequest, tool_lp{{/str}}</button>{{/iscancelreviewrequestallowed}}
-            {{#isstartreviewallowed}}<button data-action="start-review">{{#str}}startreview, tool_lp{{/str}}</button>{{/isstartreviewallowed}}
-            {{#isstopreviewallowed}}<button data-action="stop-review">{{#str}}stopreview, tool_lp{{/str}}</button>{{/isstopreviewallowed}}
+            {{#isrequestreviewallowed}}<button class="btn btn-secondary" data-action="request-review">{{#str}}requestreview, tool_lp{{/str}}</button>{{/isrequestreviewallowed}}
+            {{#iscancelreviewrequestallowed}}<button class="btn btn-secondary" data-action="cancel-review-request">{{#str}}cancelreviewrequest, tool_lp{{/str}}</button>{{/iscancelreviewrequestallowed}}
+            {{#isstartreviewallowed}}<button class="btn btn-secondary" data-action="start-review">{{#str}}startreview, tool_lp{{/str}}</button>{{/isstartreviewallowed}}
+            {{#isstopreviewallowed}}<button class="btn btn-secondary" data-action="stop-review">{{#str}}stopreview, tool_lp{{/str}}</button>{{/isstopreviewallowed}}
         </dd>
         <dt>{{#str}}proficient, tool_lp{{/str}}</dt>
         <dd>
@@ -75,7 +75,7 @@
         <dt>{{#str}}rating, tool_lp{{/str}}</dt>
         <dd>{{gradename}}
             {{#cangrade}}
-                <button class="btn" id="rate_{{uniqid}}">{{#str}}rate, tool_lp{{/str}}</button>
+                <button class="btn btn-secondary" id="rate_{{uniqid}}">{{#str}}rate, tool_lp{{/str}}</button>
             {{/cangrade}}
         </dd>
         {{#js}}
index a0e14bf..d24f138 100644 (file)
                 <li>
                     <a href="#">{{#str}}edit{{/str}}</a><b class="caret"></b>
                     <ul class="dropdown-menu">
-                        <li>
+                        <li class="dropdown-item">
                             <a href="{{pluginbaseurl}}/user_evidence_edit.php?id={{id}}&amp;userid={{userid}}&amp;return=list">
                                 {{#pix}}t/edit{{/pix}} {{#str}}editthisuserevidence, tool_lp{{/str}}
                             </a>
                         </li>
                         {{#userhasplan}}
-                        <li>
+                        <li class="dropdown-item">
                             <a href="#" data-action="link-competency">
                                 {{#pix}}t/add{{/pix}} {{#str}}linkcompetencies, tool_lp{{/str}}
                             </a>
                         </li>
                         {{/userhasplan}}
-                        <li>
+                        <li class="dropdown-item">
                             <a data-action="send-competencies-review" href="#">
                                 {{#pix}}t/edit{{/pix}} {{#str}}sendcompetenciestoreview, tool_lp{{/str}}
                             </a>
                         </li>
-                        <li>
+                        <li class="dropdown-item">
                             <a data-action="user-evidence-delete" href="#">
                                 {{#pix}}t/delete{{/pix}} {{#str}}deletethisuserevidence, tool_lp{{/str}}
                             </a>
 {{#js}}
 require(['tool_lp/user_evidence_actions'], function(UserEvidenceActions) {
     var uea = new UserEvidenceActions('list');
-    uea.enhanceMenubar('.user-evidence-actions')
+    uea.enhanceMenubar('.user-evidence-actions');
 });
 {{/js}}
index 29f28cf..fca3723 100644 (file)
@@ -40,7 +40,7 @@
     <div data-region="actions" class="clearfix">
         <div class="pull-left">
             {{#userhasplan}}
-                <button class="btn" data-action="link-competency">{{#pix}}t/add{{/pix}} {{#str}}linkcompetencies, tool_lp{{/str}}</button>
+                <button class="btn btn-secondary m-b-1" data-action="link-competency">{{#pix}}t/add{{/pix}} {{#str}}linkcompetencies, tool_lp{{/str}}</button>
             {{/userhasplan}}
         </div>
     </div>
index 0a5fea5..a43d857 100644 (file)
@@ -44,7 +44,7 @@ class behat_tool_lp extends behat_base {
      * @param string $rowname
      */
     public function click_on_edit_menu_of_the_row($nodetext, $rowname) {
-        $xpathtarget = "//ul//li//ul//li[@class='tool-lp-menu-item']//a[contains(.,'" . $nodetext . "')]";
+        $xpathtarget = "//ul//li//ul//li[contains(concat(' ', @class, ' '), ' tool-lp-menu-item ')]//a[contains(.,'" . $nodetext . "')]";
 
         $this->execute('behat_general::i_click_on_in_the', [get_string('edit'), 'link', $this->escape($rowname), 'table_row']);
         $this->execute('behat_general::i_click_on_in_the', [$xpathtarget, 'xpath_element', $this->escape($rowname), 'table_row']);
index a5edea4..f9bfc3b 100644 (file)
@@ -36,16 +36,16 @@ $PAGE->set_url($url);
 $PAGE->set_title($title);
 $PAGE->set_heading(get_string('pluginname', 'tool_lpmigrate'));
 
-$output = $PAGE->get_renderer('tool_lpmigrate');
-
-echo $output->header();
-echo $output->heading($title);
-
 $form = new \tool_lpmigrate\form\migrate_framework($context);
 if ($form->is_cancelled()) {
     redirect($url);
+}
+
+$output = $PAGE->get_renderer('tool_lpmigrate');
+echo $output->header();
+echo $output->heading($title);
 
-} else if ($data = $form->get_data()) {
+if ($data = $form->get_data()) {
 
     // Map competencies from both framework.
     $mapper = new \tool_lpmigrate\framework_mapper($data->from, $data->to);
index 0e26c58..fe33923 100644 (file)
@@ -931,7 +931,7 @@ class manager {
 
         // The message will be sent from the intended user.
         $eventdata->courseid            = SITEID;
-        $eventdata->userfrom            = \core_user::get_support_user();
+        $eventdata->userfrom            = \core_user::get_noreply_user();
         $eventdata->userto              = $USER;
         $eventdata->subject             = $this->get_reply_subject($this->currentmessagedata->envelope->subject);
         $eventdata->fullmessage         = get_string('invalidrecipientdescription', 'tool_messageinbound', $this->currentmessagedata);
index bb562e0..7fe0f16 100644 (file)
 defined('MOODLE_INTERNAL') || die;
 
 if ($hassiteconfig) {
-    $category = new admin_category('messageinbound', new lang_string('incomingmailconfiguration', 'tool_messageinbound'));
-
     // Create a settings page for all of the mail server settings.
-    $settings = new admin_settingpage('messageinbound_mailsettings', new lang_string('mailsettings', 'tool_messageinbound'));
+    $settings = new admin_settingpage('messageinbound_mailsettings',
+            new lang_string('incomingmailconfiguration', 'tool_messageinbound'));
 
     $settings->add(new admin_setting_heading('messageinbound_generalconfiguration',
             new lang_string('messageinboundgeneralconfiguration', 'tool_messageinbound'),
@@ -75,13 +74,10 @@ if ($hassiteconfig) {
             new lang_string('messageinboundhostpass', 'tool_messageinbound'),
             new lang_string('messageinboundhostpass_desc', 'tool_messageinbound'), ''));
 
-    $category->add('messageinbound', $settings);
-
+    // Add the category to the admin tree.
+    $ADMIN->add('email', $settings);
     // Link to the external page for Inbound Message handler configuration.
-    $category->add('messageinbound', new admin_externalpage('messageinbound_handlers',
+    $ADMIN->add('email', new admin_externalpage('messageinbound_handlers',
             new lang_string('message_handlers', 'tool_messageinbound'),
             "$CFG->wwwroot/$CFG->admin/tool/messageinbound/index.php"));
-
-    // Add the category to the admin tree.
-    $ADMIN->add('server', $category);
 }
index 441a19a..c5862e7 100644 (file)
@@ -25,6 +25,7 @@
 $string['autologinkeygenerationlockout'] = 'Auto-login key generation is locked out, too much requests in an hour.';
 $string['autologinnotallowedtoadmins'] = 'Auto-login is not allowed to site admins';
 $string['clickheretolaunchtheapp'] = 'Click here if the app does not open automatically.';
+$string['configmobilecssurl'] = 'A CSS file to customise your mobile app interface.';
 $string['enablesmartappbanners'] = 'Enable Smart App Banners';
 $string['enablesmartappbanners_desc'] = 'This will display a banner promoting the Moodle Mobile app when visiting the site in Mobile Safari.';
 $string['forcedurlscheme'] = 'If you want to allow only your custom branded app to be opened via a browser window, then specify its URL scheme here; otherwise leave the field empty.';
@@ -36,6 +37,11 @@ $string['iosappid_desc'] = 'This setting may be left as default unless you have
 $string['loginintheapp'] = 'Via the app';
 $string['logininthebrowser'] = 'Via a browser window (for SSO plugins)';
 $string['loginintheembeddedbrowser'] = 'Via an embedded browser (for SSO plugins)';
+$string['mobileapp'] = 'Mobile app';
+$string['mobileappearance'] = 'Mobile appearance';
+$string['mobileauthentication'] = 'Mobile authentication';
+$string['mobilecssurl'] = 'CSS';
+$string['mobilesettings'] = 'Mobile settings';
 $string['pluginname'] = 'Moodle Mobile tools';
 $string['smartappbanners'] = 'Smart App Banners (iOS only)';
 $string['pluginnotenabledorconfigured'] = 'Plugin not enabled or configured.';
index 714bf42..030daba 100644 (file)
@@ -56,22 +56,27 @@ require_login(0, false);
 core_user::require_active_user($USER);
 
 // Get an existing token or create a new one.
+$timenow = time();
 $token = external_generate_token_for_current_user($service);
+$privatetoken = $token->privatetoken;
+external_log_token_request($token);
 
-// Log token access.
-$DB->set_field('external_tokens', 'lastaccess', time(), array('id' => $token->id));
+// Invalidate the private token if external_generate_token_for_current_user did not create a new token.
+if ($token->timecreated < $timenow) {
+    $privatetoken = null;
+}
 
-$params = array(
-    'objectid' => $token->id,
-);
-$event = \core\event\webservice_token_sent::create($params);
-$event->add_record_snapshot('external_tokens', $token);
-$event->trigger();
+$siteadmin = has_capability('moodle/site:config', context_system::instance(), $USER->id);
 
 // Passport is generated in the mobile app, so the app opening can be validated using that variable.
 // Passports are valid only one time, it's deleted in the app once used.
 $siteid = md5($CFG->wwwroot . $passport);
-$apptoken = base64_encode($siteid . ':::' . $token->token);
+$apptoken = $siteid . ':::' . $token->token;
+if ($privatetoken and is_https() and !$siteadmin) {
+    $apptoken .= ':::' . $privatetoken;
+}
+
+$apptoken = base64_encode($apptoken);
 
 // Redirect using the custom URL scheme checking first if a URL scheme is forced in the site settings.
 $forcedurlscheme = get_config('tool_mobile', 'forcedurlscheme');
index 496557c..9cc8d90 100644 (file)
@@ -28,7 +28,9 @@ defined('MOODLE_INTERNAL') || die();
 
 if ($hassiteconfig) {
 
-    $temp = new admin_settingpage('mobile', new lang_string('mobile', 'admin'), 'moodle/site:config', false);
+    $ADMIN->add('root', new admin_category('mobileapp', new lang_string('mobileapp', 'tool_mobile')), 'development');
+
+    $temp = new admin_settingpage('mobilesettings', new lang_string('mobilesettings', 'tool_mobile'), 'moodle/site:config', false);
 
     // We should wait to the installation to finish since we depend on some configuration values that are set once
     // the admin user profile is configured.
@@ -41,32 +43,43 @@ if ($hassiteconfig) {
                 new lang_string('configenablemobilewebservice', 'admin', $enablemobiledoclink), $default));
     }
 
-    $temp->add(new admin_setting_configtext('mobilecssurl', new lang_string('mobilecssurl', 'admin'),
-                new lang_string('configmobilecssurl', 'admin'), '', PARAM_URL));
+    $ADMIN->add('mobileapp', $temp);
+
+    // Show only mobile settings if the mobile service is enabled.
+    if (!empty($CFG->enablemobilewebservice)) {
+        // Type of login.
+        $temp = new admin_settingpage('mobileauthentication', new lang_string('mobileauthentication', 'tool_mobile'));
+        $options = array(
+            tool_mobile\api::LOGIN_VIA_APP => new lang_string('loginintheapp', 'tool_mobile'),
+            tool_mobile\api::LOGIN_VIA_BROWSER => new lang_string('logininthebrowser', 'tool_mobile'),
+            tool_mobile\api::LOGIN_VIA_EMBEDDED_BROWSER => new lang_string('loginintheembeddedbrowser', 'tool_mobile'),
+        );
+        $temp->add(new admin_setting_configselect('tool_mobile/typeoflogin',
+                    new lang_string('typeoflogin', 'tool_mobile'),
+                    new lang_string('typeoflogin_desc', 'tool_mobile'), 1, $options));
+
+        $temp->add(new admin_setting_configtext('tool_mobile/forcedurlscheme',
+                    new lang_string('forcedurlscheme_key', 'tool_mobile'),
+                    new lang_string('forcedurlscheme', 'tool_mobile'), '', PARAM_NOTAGS));
 
-    // Type of login.
-    $options = array(
-        tool_mobile\api::LOGIN_VIA_APP => new lang_string('loginintheapp', 'tool_mobile'),
-        tool_mobile\api::LOGIN_VIA_BROWSER => new lang_string('logininthebrowser', 'tool_mobile'),
-        tool_mobile\api::LOGIN_VIA_EMBEDDED_BROWSER => new lang_string('loginintheembeddedbrowser', 'tool_mobile'),
-    );
-    $temp->add(new admin_setting_configselect('tool_mobile/typeoflogin',
-                new lang_string('typeoflogin', 'tool_mobile'),
-                new lang_string('typeoflogin_desc', 'tool_mobile'), 1, $options));
+        $ADMIN->add('mobileapp', $temp);
 
-    $temp->add(new admin_setting_configtext('tool_mobile/forcedurlscheme',
-                new lang_string('forcedurlscheme_key', 'tool_mobile'),
-                new lang_string('forcedurlscheme', 'tool_mobile'), '', PARAM_NOTAGS));
+        // Appearance related settings.
+        $temp = new admin_settingpage('mobileappearance', new lang_string('mobileappearance', 'tool_mobile'));
 
-    $temp->add(new admin_setting_heading('tool_mobile/smartappbanners',
-                new lang_string('smartappbanners', 'tool_mobile'), ''));
+        $temp->add(new admin_setting_configtext('mobilecssurl', new lang_string('mobilecssurl', 'tool_mobile'),
+                    new lang_string('configmobilecssurl', 'tool_mobile'), '', PARAM_URL));
 
-    $temp->add(new admin_setting_configcheckbox('tool_mobile/enablesmartappbanners',
-                new lang_string('enablesmartappbanners', 'tool_mobile'),
-                new lang_string('enablesmartappbanners_desc', 'tool_mobile'), 0));
+        $temp->add(new admin_setting_heading('tool_mobile/smartappbanners',
+                    new lang_string('smartappbanners', 'tool_mobile'), ''));
 
-    $temp->add(new admin_setting_configtext('tool_mobile/iosappid', new lang_string('iosappid', 'tool_mobile'),
-                new lang_string('iosappid_desc', 'tool_mobile'), '633359593', PARAM_ALPHANUM));
+        $temp->add(new admin_setting_configcheckbox('tool_mobile/enablesmartappbanners',
+                    new lang_string('enablesmartappbanners', 'tool_mobile'),
+                    new lang_string('enablesmartappbanners_desc', 'tool_mobile'), 0));
 
-    $ADMIN->add('webservicesettings', $temp);
+        $temp->add(new admin_setting_configtext('tool_mobile/iosappid', new lang_string('iosappid', 'tool_mobile'),
+                    new lang_string('iosappid_desc', 'tool_mobile'), '633359593', PARAM_ALPHANUM));
+
+        $ADMIN->add('mobileapp', $temp);
+    }
 }
index eacb24e..64657d9 100644 (file)
@@ -164,7 +164,6 @@ class tool_mobile_external_testcase extends externallib_advanced_testcase {
         $service = $DB->get_record('external_services', array('shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE));
 
         $token = external_generate_token_for_current_user($service);
-        $this->assertDebuggingCalled(); // MDL-55992.
 
         // Check we got the private token.
         $this->assertTrue(isset($token->privatetoken));
@@ -253,7 +252,6 @@ class tool_mobile_external_testcase extends externallib_advanced_testcase {
         $service = $DB->get_record('external_services', array('shortname' => MOODLE_OFFICIAL_MOBILE_SERVICE));
 
         $token = external_generate_token_for_current_user($service);
-        $this->assertDebuggingCalled(); // MDL-55992.
         $_GET['wstoken'] = $token->token;   // Mock parameters.
 
         $result = external::get_autologin_key($token->privatetoken);
index 1065bd1..b4c724b 100644 (file)
@@ -24,7 +24,7 @@
 
 require_once(__DIR__ . '/../../../config.php');
 require_once($CFG->libdir.'/adminlib.php');
-require_once($CFG->dirroot . '/admin/tool/monitor/lib.php');
+require_once($CFG->dirroot.'/'.$CFG->admin.'/tool/monitor/lib.php');
 
 $courseid = optional_param('courseid', 0, PARAM_INT);
 $action = optional_param('action', '', PARAM_ALPHA);
index ee2eb74..d4e748b 100644 (file)
@@ -152,6 +152,17 @@ function tool_recyclebin_pre_course_module_delete($cm) {
     }
 }
 
+/**
+ * Hook called to check whether async course module deletion should be performed or not.
+ *
+ * @return true if background deletion is required (is the recyclebin is enabled), false otherwise.
+ */
+function tool_recyclebin_course_module_background_deletion_recommended() {
+    if (\tool_recyclebin\course_bin::is_enabled()) {
+        return true;
+    }
+}
+
 /**
  * Hook called before we delete a course.
  *
index 500a273..c0bc961 100644 (file)
@@ -58,6 +58,7 @@ Feature: Backup user data
     And I follow "Course 1"
     And I turn editing mode on
     And I delete "Quiz 1" activity
+    And I run all adhoc tasks
     And I navigate to "Recycle bin" node in "Course administration"
     And I should see "Quiz 1"
     And I click on "Restore" "link" in the "region-main" "region"
index ded5e99..b10af91 100644 (file)
@@ -69,6 +69,7 @@ Feature: Basic recycle bin functionality
       | Assignment name | Test assign |
       | Description | Test |
     And I delete "Test assign" activity
+    And I run all adhoc tasks
     And I navigate to "Recycle bin" node in "Course administration"
     When I click on "Delete" "link"
     Then I should see "Are you sure you want to delete the selected item from the recycle bin?"
@@ -92,6 +93,7 @@ Feature: Basic recycle bin functionality
       | Description | Test 2 |
     And I delete "Test assign 1" activity
     And I delete "Test assign 2" activity
+    And I run all adhoc tasks
     And I navigate to "Recycle bin" node in "Course administration"
     And I should see "Test assign 1"
     And I should see "Test assign 2"
index 1f83de3..9a4e0c3 100644 (file)
@@ -71,6 +71,9 @@ class tool_recyclebin_course_bin_tests extends advanced_testcase {
         // Delete the course module.
         course_delete_module($this->quiz->cmid);
 
+        // Now, run the course module deletion adhoc task.
+        phpunit_util::run_all_adhoc_tasks();
+
         // Check the course module is now in the recycle bin.
         $this->assertEquals(1, $DB->count_records('tool_recyclebin_course'));
 
@@ -112,6 +115,9 @@ class tool_recyclebin_course_bin_tests extends advanced_testcase {
         // Delete the course module.
         course_delete_module($this->quiz->cmid);
 
+        // Now, run the course module deletion adhoc task.
+        phpunit_util::run_all_adhoc_tasks();
+
         // Try purging.
         $recyclebin = new \tool_recyclebin\course_bin($this->course->id);
         foreach ($recyclebin->get_items() as $item) {
@@ -134,6 +140,9 @@ class tool_recyclebin_course_bin_tests extends advanced_testcase {
         // Delete the quiz.
         course_delete_module($this->quiz->cmid);
 
+        // Now, run the course module deletion adhoc task.
+        phpunit_util::run_all_adhoc_tasks();
+
         // Set deleted date to the distant past.
         $recyclebin = new \tool_recyclebin\course_bin($this->course->id);
         foreach ($recyclebin->get_items() as $item) {
@@ -147,6 +156,9 @@ class tool_recyclebin_course_bin_tests extends advanced_testcase {
 
         course_delete_module($book->cmid);
 
+        // Now, run the course module deletion adhoc task.
+        phpunit_util::run_all_adhoc_tasks();
+
         // Should have 2 items now.
         $this->assertEquals(2, count($recyclebin->get_items()));
 
index ba7ea8c..4b5103c 100644 (file)
Binary files a/admin/tool/templatelibrary/amd/build/display.min.js and b/admin/tool/templatelibrary/amd/build/display.min.js differ
index b8458ae..01f2d04 100644 (file)
Binary files a/admin/tool/templatelibrary/amd/build/search.min.js and b/admin/tool/templatelibrary/amd/build/search.min.js differ
index 66b3fbc..1c2e4de 100644 (file)
@@ -33,6 +33,9 @@ define(['jquery', 'core/ajax', 'core/log', 'core/notification', 'core/templates'
      */
     var findDocsSection = function(templateSource, templateName) {
 
+        if (!templateSource) {
+            return false;
+        }
         // Find the comment section marked with @template component/template.
         var marker = "@template " + templateName,
             i = 0,
index 8b115e6..04d27b0 100644 (file)
@@ -21,8 +21,8 @@
  * @copyright  2015 Damyon Wiese <damyon@moodle.com>
  * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
-define(['jquery', 'core/ajax', 'core/log', 'core/notification', 'core/templates'],
-       function($, ajax, log, notification, templates) {
+define(['jquery', 'core/ajax', 'core/log', 'core/notification', 'core/templates', 'core/config'],
+       function($, ajax, log, notification, templates, config) {
 
     /**
      * The ajax call has returned with a new list of templates.
@@ -42,15 +42,16 @@ define(['jquery', 'core/ajax', 'core/log', 'core/notification', 'core/templates'
      *
      * @method refreshSearch
      */
-    var refreshSearch = function() {
+    var refreshSearch = function(themename) {
         var componentStr = $('[data-field="component"]').val();
         var searchStr = $('[data-field="search"]').val();
 
         // Trigger the search.
+        document.location.hash = searchStr;
 
         ajax.call([
             {methodname: 'tool_templatelibrary_list_templates',
-              args: {component: componentStr, search: searchStr},
+              args: {component: componentStr, search: searchStr, themename: themename},
               done: reloadListTemplate,
               fail: notification.exception}
         ], true, false);
@@ -78,12 +79,13 @@ define(['jquery', 'core/ajax', 'core/log', 'core/notification', 'core/templates'
     };
 
     var changeHandler = function() {
-        queueRefresh(refreshSearch, 400);
+        queueRefresh(refreshSearch.bind(this, config.theme), 400);
     };
     // Add change handlers to refresh the list.
     $('[data-region="list-templates"]').on('change', '[data-field="component"]', changeHandler);
     $('[data-region="list-templates"]').on('input', '[data-field="search"]', changeHandler);
 
-    refreshSearch();
+    $('[data-field="search"]').val(document.location.hash.replace('#', ''));
+    refreshSearch(config.theme);
     return {};
 });
index 23b7dcf..b760007 100644 (file)
@@ -47,7 +47,12 @@ class api {
      * @return array[string] Where each template is in the form "component/templatename".
      */
     public static function list_templates($component = '', $search = '', $themename = '') {
-        global $CFG;
+        global $CFG, $PAGE;
+
+        if (empty($themename)) {
+            $themename = $PAGE->theme->name;
+        }
+        $themeconfig = \theme_config::load($themename);
 
         $templatedirs = array();
         $results = array();
@@ -77,6 +82,9 @@ class api {
             foreach ($plugintypes as $type => $dir) {
                 $plugins = core_component::get_plugin_list_with_file($type, 'templates', false);
                 foreach ($plugins as $plugin => $dir) {
+                    if ($type == 'theme' && $plugin != $themename && !in_array($plugin, $themeconfig->parents)) {
+                        continue;
+                    }
                     if (!empty($dir) && is_dir($dir)) {
                         $pluginname = $type . '_' . $plugin;
                         $dirs = mustache_template_finder::get_template_directories_for_component($pluginname, $themename);
@@ -111,7 +119,7 @@ class api {
      *
      * @param string $component The component that holds the template.
      * @param string $template The name of the template.
-     * @return string the template
+     * @return string the template or false if template doesn't exist.
      */
     public static function load_canonical_template($component, $template) {
         // Get the list of possible template directories.
@@ -133,7 +141,8 @@ class api {
         }
 
         if ($filename === false) {
-            throw new moodle_exception('filenotfound', 'error');
+            // There are occasions where we don't have a core template.
+            return false;
         }
 
         $templatestr = file_get_contents($filename);
index be583a2..b92f608 100644 (file)
@@ -59,7 +59,13 @@ class external extends external_api {
             VALUE_DEFAULT,
             ''
         );
-        $params = array('component' => $component, 'search' => $search);
+        $themename = new external_value(
+            PARAM_COMPONENT,
+            'The current theme',
+            VALUE_DEFAULT,
+            ''
+        );
+        $params = array('component' => $component, 'search' => $search, 'themename' => $themename);
         return new external_function_parameters($params);
     }
 
@@ -67,16 +73,18 @@ class external extends external_api {
      * Loads the list of templates.
      * @param string $component Limit the search to a component.
      * @param string $search The search string.
+     * @param string $themename The name of theme
      * @return array[string]
      */
-    public static function list_templates($component, $search) {
+    public static function list_templates($component, $search, $themename = '') {
         $params = self::validate_parameters(self::list_templates_parameters(),
                                             array(
                                                 'component' => $component,
                                                 'search' => $search,
+                                                'themename' => $themename,
                                             ));
 
-        return api::list_templates($component, $search);
+        return api::list_templates($component, $search, $themename);
     }
 
     /**
@@ -107,7 +115,7 @@ class external extends external_api {
      *
      * @param string $component The component that holds the template.
      * @param string $template The name of the template.
-     * @return string the template
+     * @return string the template, false if template doesn't exist.
      */
     public static function load_canonical_template($component, $template) {
         $params = self::validate_parameters(self::load_canonical_template_parameters(),
index ac29055..a86924e 100644 (file)
Binary files a/admin/tool/usertours/amd/build/popper.min.js and b/admin/tool/usertours/amd/build/popper.min.js differ
index 2f37014..20f5d4f 100644 (file)
Binary files a/admin/tool/usertours/amd/build/tour.min.js and b/admin/tool/usertours/amd/build/tour.min.js differ
index 16119ab..c0fb1d7 100644 (file)
-/**
- * @fileOverview Kickass library to create and place poppers near their reference elements.
- * @version 0.6.4
- * @license
- * Copyright (c) 2016 Federico Zivolo and contributors
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy
- * of this software and associated documentation files (the "Software"), to deal
- * in the Software without restriction, including without limitation the rights
- * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
- * copies of the Software, and to permit persons to whom the Software is
- * furnished to do so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
- * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
- * SOFTWARE.
- */
-
-//
-// Cross module loader
-// Supported: Node, AMD, Browser globals
-//
-;(function (root, factory) {
-    if (typeof define === 'function' && define.amd) {
-        // AMD. Register as an anonymous module.
-        define(factory);
-    } else if (typeof module === 'object' && module.exports) {
-        // Node. Does not work with strict CommonJS, but
-        // only CommonJS-like environments that support module.exports,
-        // like Node.
-        module.exports = factory();
-    } else {
-        // Browser globals (root is window)
-        root.Popper = factory();
-    }
-}(this, function () {
-
-    'use strict';
-
-    var root = window;
-
-    // default options
-    var DEFAULTS = {
-        // placement of the popper
-        placement: 'bottom',
-
-        gpuAcceleration: true,
-
-        // shift popper from its origin by the given amount of pixels (can be negative)
-        offset: 0,
-
-        // the element which will act as boundary of the popper
-        boundariesElement: 'viewport',
-
-        // amount of pixel used to define a minimum distance between the boundaries and the popper
-        boundariesPadding: 5,
-
-        // popper will try to prevent overflow following this order,
-        // by default, then, it could overflow on the left and on top of the boundariesElement
-        preventOverflowOrder: ['left', 'right', 'top', 'bottom'],
-
-        // the behavior used by flip to change the placement of the popper
-        flipBehavior: 'flip',
-
-        arrowElement: '[x-arrow]',
-
-        // list of functions used to modify the offsets before they are applied to the popper
-        modifiers: [ 'shift', 'offset', 'preventOverflow', 'keepTogether', 'arrow', 'flip', 'applyStyle'],
-
-        modifiersIgnored: [],
-    };
-
-    /**
-     * Create a new Popper.js instance
-     * @constructor Popper
-     * @param {HTMLElement} reference - The reference element used to position the popper
-     * @param {HTMLElement|Object} popper
-     *      The HTML element used as popper, or a configuration used to generate the popper.
-     * @param {String} [popper.tagName='div'] The tag name of the generated popper.
-     * @param {Array} [popper.classNames=['popper']] Array of classes to apply to the generated popper.
-     * @param {Array} [popper.attributes] Array of attributes to apply, specify `attr:value` to assign a value to it.
-     * @param {HTMLElement|String} [popper.parent=window.document.body] The parent element, given as HTMLElement or as query string.
-     * @param {String} [popper.content=''] The content of the popper, it can be text, html, or node; if it is not text, set `contentType` to `html` or `node`.
-     * @param {String} [popper.contentType='text'] If `html`, the `content` will be parsed as HTML. If `node`, it will be appended as-is.
-     * @param {String} [popper.arrowTagName='div'] Same as `popper.tagName` but for the arrow element.
-     * @param {Array} [popper.arrowClassNames='popper__arrow'] Same as `popper.classNames` but for the arrow element.
-     * @param {String} [popper.arrowAttributes=['x-arrow']] Same as `popper.attributes` but for the arrow element.
-     * @param {Object} options
-     * @param {String} [options.placement=bottom]
-     *      Placement of the popper accepted values: `top(-start, -end), right(-start, -end), bottom(-start, -right),
-     *      left(-start, -end)`
-     *
-     * @param {HTMLElement|String} [options.arrowElement='[x-arrow]']
-     *      The DOM Node used as arrow for the popper, or a CSS selector used to get the DOM node. It must be child of
-     *      its parent Popper. Popper.js will apply to the given element the style required to align the arrow with its
-     *      reference element.
-     *      By default, it will look for a child node of the popper with the `x-arrow` attribute.
-     *
-     * @param {Boolean} [options.gpuAcceleration=true]
-     *      When this property is set to true, the popper position will be applied using CSS3 translate3d, allowing the
-     *      browser to use the GPU to accelerate the rendering.
-     *      If set to false, the popper will be placed using `top` and `left` properties, not using the GPU.
-     *
-     * @param {Number} [options.offset=0]
-     *      Amount of pixels the popper will be shifted (can be negative).
-     *
-     * @param {String|Element} [options.boundariesElement='viewport']
-     *      The element which will define the boundaries of the popper position, the popper will never be placed outside
-     *      of the defined boundaries (except if `keepTogether` is enabled)
-     *
-     * @param {Number} [options.boundariesPadding=5]
-     *      Additional padding for the boundaries
-     *
-     * @param {Array} [options.preventOverflowOrder=['left', 'right', 'top', 'bottom']]
-     *      Order used when Popper.js tries to avoid overflows from the boundaries, they will be checked in order,
-     *      this means that the last ones will never overflow
-     *
-     * @param {String|Array} [options.flipBehavior='flip']
-     *      The behavior used by the `flip` modifier to change the placement of the popper when the latter is trying to
-     *      overlap its reference element. Defining `flip` as value, the placement will be flipped on
-     *      its axis (`right - left`, `top - bottom`).
-     *      You can even pass an array of placements (eg: `['right', 'left', 'top']` ) to manually specify
-     *      how alter the placement when a flip is needed. (eg. in the above example, it would first flip from right to left,
-     *      then, if even in its new placement, the popper is overlapping its reference element, it will be moved to top)
-     *
-     * @param {Array} [options.modifiers=[ 'shift', 'offset', 'preventOverflow', 'keepTogether', 'arrow', 'flip', 'applyStyle']]
-     *      List of functions used to modify the data before they are applied to the popper, add your custom functions
-     *      to this array to edit the offsets and placement.
-     *      The function should reflect the @params and @returns of preventOverflow
-     *
-     * @param {Array} [options.modifiersIgnored=[]]
-     *      Put here any built-in modifier name you want to exclude from the modifiers list
-     *      The function should reflect the @params and @returns of preventOverflow
-     *
-     * @param {Boolean} [options.removeOnDestroy=false]
-     *      Set to true if you want to automatically remove the popper when you call the `destroy` method.
-     */
-    function Popper(reference, popper, options) {
-        this._reference = reference.jquery ? reference[0] : reference;
-        this.state = { onCreateCalled: false };
-
-        // if the popper variable is a configuration object, parse it to generate an HTMLElement
-        // generate a default popper if is not defined
-        var isNotDefined = typeof popper === 'undefined' || popper === null;
-        var isConfig = popper && Object.prototype.toString.call(popper) === '[object Object]';
-        if (isNotDefined || isConfig) {
-            this._popper = this.parse(isConfig ? popper : {});
-        }
-        // otherwise, use the given HTMLElement as popper
-        else {
-            this._popper = popper.jquery ? popper[0] : popper;
-        }
-
-        // with {} we create a new object with the options inside it
-        this._options = Object.assign({}, DEFAULTS, options);
-
-        // refactoring modifiers' list
-        this._options.modifiers = this._options.modifiers.map(function(modifier){
-            // remove ignored modifiers
-            if (this._options.modifiersIgnored.indexOf(modifier) !== -1) return;
-
-            // set the x-placement attribute before everything else because it could be used to add margins to the popper
-            // margins needs to be calculated to get the correct popper offsets
-            if (modifier === 'applyStyle') {
-                this._popper.setAttribute('x-placement', this._options.placement);
-            }
-
-            // return predefined modifier identified by string or keep the custom one
-            return this.modifiers[modifier] || modifier;
-        }.bind(this));
-
-        // make sure to apply the popper position before any computation
-        this.state.position = this._getPosition(this._popper, this._reference);
-        setStyle(this._popper, { position: this.state.position});
-
-        // determine how we should set the origin of offsets
-        this.state.isParentTransformed = this._getIsParentTransformed(this._popper);
-
-        // fire the first update to position the popper in the right place
-        this.update();
-
-        // setup event listeners, they will take care of update the position in specific situations
-        this._setupEventListeners();
-        return this;
-    }
-
-
-    //
-    // Methods
-    //
-    /**
-     * Destroy the popper
-     * @method
-     * @memberof Popper
-     */
-    Popper.prototype.destroy = function() {
-        this._popper.removeAttribute('x-placement');
-        this._popper.style.left = '';
-        this._popper.style.position = '';
-        this._popper.style.top = '';
-        this._popper.style[getSupportedPropertyName('transform')] = '';
-        this._removeEventListeners();
-
-        // remove the popper if user explicity asked for the deletion on destroy
-        if (this._options.removeOnDestroy) {
-            this._popper.parentNode.removeChild(this._popper);
-        }
-        return this;
-    };
-
-    /**
-     * Updates the position of the popper, computing the new offsets and applying the new style
-     * @method
-     * @memberof Popper
-     */
-    Popper.prototype.update = function() {
-        var data = { instance: this, styles: {} };
-
-        // make sure to apply the popper position before any computation
-        this.state.position = this._getPosition(this._popper, this._reference);
-        setStyle(this._popper, { position: this.state.position});
-
-        // to avoid useless computations we throttle the popper position refresh to 60fps
-        root.requestAnimationFrame(function() {
-            var now = root.performance.now();
-            if(now - this.state.lastFrame <= 16) {
-                // this update fired to early! drop it
-                return;
-            }
-            this.state.lastFrame = now;
-
-            // store placement inside the data object, modifiers will be able to edit `placement` if needed
-            // and refer to _originalPlacement to know the original value
-            data.placement = this._options.placement;
-            data._originalPlacement = this._options.placement;
-
-            // compute the popper and trigger offsets and put them inside data.offsets
-            data.offsets = this._getOffsets(this._popper, this._reference, data.placement);
-
-            // get boundaries
-            data.boundaries = this._getBoundaries(data, this._options.boundariesPadding, this._options.boundariesElement);
-
-            data = this.runModifiers(data, this._options.modifiers);
-
-            if (!isFunction(this.state.createCalback)) {
-                this.state.onCreateCalled = true;
-            }
-            if (!this.state.onCreateCalled) {
-                this.state.onCreateCalled = true;
-                if (isFunction(this.state.createCalback)) {
-                    this.state.createCalback(this);
-                }
-            } else if (isFunction(this.state.updateCallback)) {
-                this.state.updateCallback(data);
-            }
-        }.bind(this));
-    };
-
-    /**
-     * If a function is passed, it will be executed after the initialization of popper with as first argument the Popper instance.
-     * @method
-     * @memberof Popper
-     * @param {Function} callback
-     */
-    Popper.prototype.onCreate = function(callback) {
-        // the createCallbacks return as first argument the popper instance
-        this.state.createCalback = callback;
-        return this;
-    };
-
-    /**
-     * If a function is passed, it will be executed after each update of popper with as first argument the set of coordinates and informations
-     * used to style popper and its arrow.
-     * NOTE: it doesn't get fired on the first call of the `Popper.update()` method inside the `Popper` constructor!
-     * @method
-     * @memberof Popper
-     * @param {Function} callback
-     */
-    Popper.prototype.onUpdate = function(callback) {
-        this.state.updateCallback = callback;
-        return this;
-    };
-
-    /**
-     * Helper used to generate poppers from a configuration file
-     * @method
-     * @memberof Popper
-     * @param config {Object} configuration
-     * @returns {HTMLElement} popper
-     */
-    Popper.prototype.parse = function(config) {
-        var defaultConfig = {
-            tagName: 'div',
-            classNames: [ 'popper' ],
-            attributes: [],
-            parent: root.document.body,
-            content: '',
-            contentType: 'text',
-            arrowTagName: 'div',
-            arrowClassNames: [ 'popper__arrow' ],
-            arrowAttributes: [ 'x-arrow']
-        };
-        config = Object.assign({}, defaultConfig, config);
-
-        var d = root.document;
-
-        var popper = d.createElement(config.tagName);
-        addClassNames(popper, config.classNames);
-        addAttributes(popper, config.attributes);
-        if (config.contentType === 'node') {
-            popper.appendChild(config.content.jquery ? config.content[0] : config.content);
-        }else if (config.contentType === 'html') {
-            popper.innerHTML = config.content;
-        } else {
-            popper.textContent = config.content;
-        }
-
-        if (config.arrowTagName) {
-            var arrow = d.createElement(config.arrowTagName);
-            addClassNames(arrow, config.arrowClassNames);
-            addAttributes(arrow, config.arrowAttributes);
-            popper.appendChild(arrow);
-        }
-
-        var parent = config.parent.jquery ? config.parent[0] : config.parent;
-
-        // if the given parent is a string, use it to match an element
-        // if more than one element is matched, the first one will be used as parent
-        // if no elements are matched, the script will throw an error
-        if (typeof parent === 'string') {
-            parent = d.querySelectorAll(config.parent);
-            if (parent.length > 1) {
-                console.warn('WARNING: the given `parent` query(' + config.parent + ') matched more than one element, the first one will be used');
-            }
-            if (parent.length === 0) {
-                throw 'ERROR: the given `parent` doesn\'t exists!';
-            }
-            parent = parent[0];
-        }
-        // if the given parent is a DOM nodes list or an array of nodes with more than one element,
-        // the first one will be used as parent
-        if (parent.length > 1 && parent instanceof Element === false) {
-            console.warn('WARNING: you have passed as parent a list of elements, the first one will be used');
-            parent = parent[0];
-        }
-
-        // append the generated popper to its parent
-        parent.appendChild(popper);
-
-        return popper;
-
-        /**
-         * Adds class names to the given element
-         * @function
-         * @ignore
-         * @param {HTMLElement} target
-         * @param {Array} classes
-         */
-        function addClassNames(element, classNames) {
-            classNames.forEach(function(className) {
-                element.classList.add(className);
-            });
-        }
-
-        /**
-         * Adds attributes to the given element
-         * @function
-         * @ignore
-         * @param {HTMLElement} target
-         * @param {Array} attributes
-         * @example
-         * addAttributes(element, [ 'data-info:foobar' ]);
-         */
-        function addAttributes(element, attributes) {
-            attributes.forEach(function(attribute) {
-                element.setAttribute(attribute.split(':')[0], attribute.split(':')[1] || '');
-            });
-        }
-
-    };
-
-    /**
-     * Helper used to get the position which will be applied to the popper
-     * @method
-     * @memberof Popper
-     * @param config {HTMLElement} popper element
-     * @returns {HTMLElement} reference element
-     */
-    Popper.prototype._getPosition = function(popper, reference) {
-        var container = getOffsetParent(reference);
-
-        // Decide if the popper will be fixed
-        // If the reference element is inside a fixed context, the popper will be fixed as well to allow them to scroll together
-        var isParentFixed = isFixed(container);
-        return isParentFixed ? 'fixed' : 'absolute';
-    };
-
-    /**
-     * Helper used to determine if the popper's parent is transformed.
-     * @param  {[type]} popper [description]
-     * @return {[type]}        [description]
-     */
-    Popper.prototype._getIsParentTransformed = function(popper) {
-      return isTransformed(popper.parentNode);
-    };
-
-    /**
-     * Get offsets to the popper
-     * @method
-     * @memberof Popper
-     * @access private
-     * @param {Element} popper - the popper element
-     * @param {Element} reference - the reference element (the popper will be relative to this)
-     * @returns {Object} An object containing the offsets which will be applied to the popper
-     */
-    Popper.prototype._getOffsets = function(popper, reference, placement) {
-        placement = placement.split('-')[0];
-        var popperOffsets = {};
-
-        popperOffsets.position = this.state.position;
-        var isParentFixed = popperOffsets.position === 'fixed';
-
-        var isParentTransformed = this.state.isParentTransformed;
-
-        //
-        // Get reference element position
-        //
-        var offsetParent = (isParentFixed && isParentTransformed) ? getOffsetParent(reference) : getOffsetParent(popper);
-        var referenceOffsets = getOffsetRectRelativeToCustomParent(reference, offsetParent, isParentFixed, isParentTransformed);
-
-        //
-        // Get popper sizes
-        //
-        var popperRect = getOuterSizes(popper);
-
-        //
-        // Compute offsets of popper
-        //
-
-        // depending by the popper placement we have to compute its offsets slightly differently
-        if (['right', 'left'].indexOf(placement) !== -1) {
-            popperOffsets.top = referenceOffsets.top + referenceOffsets.height / 2 - popperRect.height / 2;
-            if (placement === 'left') {
-                popperOffsets.left = referenceOffsets.left - popperRect.width;
-            } else {
-                popperOffsets.left = referenceOffsets.right;
-            }
-        } else {
-            popperOffsets.left = referenceOffsets.left + referenceOffsets.width / 2 - popperRect.width / 2;
-            if (placement === 'top') {
-                popperOffsets.top = referenceOffsets.top - popperRect.height;
-            } else {
-                popperOffsets.top = referenceOffsets.bottom;
-            }
-        }
-
-        // Add width and height to our offsets object
-        popperOffsets.width   = popperRect.width;