Merge branch 'MDL-35104-master-2' of git://github.com/cameron1729/moodle
authorAndrew Nicols <andrew@nicols.co.uk>
Tue, 21 Jun 2016 03:18:03 +0000 (11:18 +0800)
committerAndrew Nicols <andrew@nicols.co.uk>
Tue, 21 Jun 2016 03:18:03 +0000 (11:18 +0800)
35 files changed:
admin/tool/templatelibrary/amd/build/display.min.js
admin/tool/templatelibrary/amd/src/display.js
completion/criteria/completion_criteria_activity.php
course/completion_form.php
course/format/README.txt
course/format/upgrade.txt
course/renderer.php
course/view.php
course/yui/build/moodle-course-modchooser/moodle-course-modchooser-debug.js
course/yui/build/moodle-course-modchooser/moodle-course-modchooser-min.js
course/yui/build/moodle-course-modchooser/moodle-course-modchooser.js
course/yui/src/modchooser/js/modchooser.js
lang/en/admin.php
lang/en/deprecated.txt
lang/en/install.php
lang/en/moodle.php
lib/moodlelib.php
lib/navigationlib.php
mod/assign/feedback/editpdf/styles.css
mod/book/tool/print/print.css
mod/choice/styles.css
mod/data/preset/imagegallery/csstemplate.css
mod/feedback/classes/observer.php [new file with mode: 0644]
mod/feedback/db/events.php [moved from course/category.php with 57% similarity]
mod/feedback/lib.php
mod/feedback/tests/events_test.php
mod/feedback/version.php
mod/forum/styles.css
mod/lesson/lib.php
mod/scorm/styles.css
mod/upgrade.txt
report/upgrade.txt
user/classes/course_form.php [new file with mode: 0644]
user/course.php [new file with mode: 0644]
user/tests/behat/course_preference.feature [new file with mode: 0644]

index 55ae25d..503f280 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 05507ee..500f7d8 100644 (file)
@@ -141,8 +141,9 @@ define(['jquery', 'core/ajax', 'core/log', 'core/notification', 'core/templates'
     };
 
     // Add the event listeners.
-    $('[data-region="list-templates"]').on('click', '[data-templatename]', function() {
+    $('[data-region="list-templates"]').on('click', '[data-templatename]', function(e) {
         var templatename = $(this).data('templatename');
+        e.preventDefault();
         loadTemplate(templatename);
     });
 
index 05eda15..28437de 100644 (file)
@@ -61,10 +61,11 @@ class completion_criteria_activity extends completion_criteria {
      */
     public function config_form_display(&$mform, $data = null) {
         $modnames = get_module_types_names();
-        $mform->addElement('checkbox', 'criteria_activity['.$data->id.']',
-                $modnames[self::get_mod_name($data->module)].
-                ' - '.
-                format_string($data->name));
+        $mform->addElement('advcheckbox',
+                'criteria_activity['.$data->id.']',
+                $modnames[self::get_mod_name($data->module)] . ' - ' . format_string($data->name),
+                null,
+                array('group' => 1));
 
         if ($this->id) {
             $mform->setDefault('criteria_activity['.$data->id.']', 1);
index ce4880a..53d4b47 100644 (file)
@@ -88,6 +88,9 @@ class course_completion_form extends moodleform {
         $activities = $completion->get_activities();
         if (!empty($activities)) {
 
+            if (!$completion->is_course_locked()) {
+                $this->add_checkbox_controller(1, null, null, 0);
+            }
             foreach ($activities as $activity) {
                 $params_a = array('moduleinstance' => $activity->id);
                 $criteria = new completion_criteria_activity(array_merge($params, $params_a));
index 9bb62ab..6705b5b 100644 (file)
@@ -139,8 +139,3 @@ Optional file (styles)
 
   If this file exists it will be included in the CSS Moodle generates.
 
-
-Optional delete course hook
----------------------------
-
-* in your yourformat/lib.php add function format_yourformat_delete_course($courseid)
\ No newline at end of file
index 8d82f27..8bdcfe0 100644 (file)
@@ -2,6 +2,9 @@ This files describes API changes for course formats
 
 Overview of this plugin type at http://docs.moodle.org/dev/Course_formats
 
+=== 3.2 ===
+* Callback delete_course is deprecated and should be replaced with observer for event \core\event\course_content_deleted
+
 === 3.1 ===
 * Course format may use the inplace_editable template to allow quick editing of section names, see
   https://docs.moodle.org/dev/Inplace_editable and MDL-51802 for example implementation.
index 787866a..637a328 100644 (file)
@@ -58,7 +58,6 @@ class core_course_renderer extends plugin_renderer_base {
     public function __construct(moodle_page $page, $target) {
         $this->strings = new stdClass;
         parent::__construct($page, $target);
-        $this->add_modchoosertoggle();
     }
 
     /**
@@ -66,8 +65,12 @@ class core_course_renderer extends plugin_renderer_base {
      *
      * Theme can overwrite as an empty function to exclude it (for example if theme does not
      * use modchooser at all)
+     *
+     * @deprecated since 3.2
      */
     protected function add_modchoosertoggle() {
+        debugging('core_course_renderer::add_modchoosertoggle() is deprecated.', DEBUG_DEVELOPER);
+
         global $CFG;
 
         // Only needs to be done once per page.
@@ -182,9 +185,7 @@ class core_course_renderer extends plugin_renderer_base {
         array(array('courseid' => $course->id, 'closeButtonTitle' => get_string('close', 'editor')))
         );
         $this->page->requires->strings_for_js(array(
-                'addresourceoractivity',
-                'modchooserenable',
-                'modchooserdisable',
+                'addresourceoractivity'
         ), 'moodle');
 
         // Add the header
@@ -406,9 +407,6 @@ class core_course_renderer extends plugin_renderer_base {
     /**
      * Renders HTML for the menus to add activities and resources to the current course
      *
-     * Note, if theme overwrites this function and it does not use modchooser,
-     * see also {@link core_course_renderer::add_modchoosertoggle()}
-     *
      * @param stdClass $course
      * @param int $section relative section number (field course_sections.section)
      * @param int $sectionreturn The section to link back to
index d4d67cf..2bd50f0 100644 (file)
@@ -17,7 +17,6 @@
     $move        = optional_param('move', 0, PARAM_INT);
     $marker      = optional_param('marker',-1 , PARAM_INT);
     $switchrole  = optional_param('switchrole',-1, PARAM_INT); // Deprecated, use course/switchrole.php instead.
-    $modchooser  = optional_param('modchooser', -1, PARAM_BOOL);
     $return      = optional_param('return', 0, PARAM_LOCALURL);
 
     $params = array();
                 redirect($PAGE->url);
             }
         }
-        if (($modchooser == 1) && confirm_sesskey()) {
-            set_user_preference('usemodchooser', $modchooser);
-        } else if (($modchooser == 0) && confirm_sesskey()) {
-            set_user_preference('usemodchooser', $modchooser);
-        }
 
         if (has_capability('moodle/course:sectionvisibility', $context)) {
             if ($hide && confirm_sesskey()) {
index 1689ac9..b986555 100644 (file)
Binary files a/course/yui/build/moodle-course-modchooser/moodle-course-modchooser-debug.js and b/course/yui/build/moodle-course-modchooser/moodle-course-modchooser-debug.js differ
index 1f08287..a690c8a 100644 (file)
Binary files a/course/yui/build/moodle-course-modchooser/moodle-course-modchooser-min.js and b/course/yui/build/moodle-course-modchooser/moodle-course-modchooser-min.js differ
index 1689ac9..b986555 100644 (file)
Binary files a/course/yui/build/moodle-course-modchooser/moodle-course-modchooser.js and b/course/yui/build/moodle-course-modchooser/moodle-course-modchooser.js differ
index ef6ac4d..8adbac4 100644 (file)
@@ -54,9 +54,6 @@ Y.extend(MODCHOOSER, M.core.chooserdialogue, {
         // Initialize existing sections and register for dynamically created sections
         this.setup_for_section();
         M.course.coursebase.register_module(this);
-
-        // Catch the page toggle
-        Y.all('.block_settings #settingsnav .type_course .modchoosertoggle a').on('click', this.toggle_mod_chooser, this);
     },
 
     /**
@@ -130,62 +127,6 @@ Y.extend(MODCHOOSER, M.core.chooserdialogue, {
         this.display_chooser(e);
     },
 
-    /**
-     * Toggle availability of the activity chooser.
-     *
-     * @method toggle_mod_chooser
-     * @param {EventFacade} e
-     */
-    toggle_mod_chooser : function(e) {
-        // Get the add section link
-        var modchooserlinks = Y.all('div.addresourcemodchooser');
-
-        // Get the dropdowns
-        var dropdowns = Y.all('div.addresourcedropdown');
-
-        if (modchooserlinks.size() === 0) {
-            // Continue with non-js action if there are no modchoosers to add
-            return;
-        }
-
-        // We need to update the text and link
-        var togglelink = Y.one('.block_settings #settingsnav .type_course .modchoosertoggle a');
-
-        // The actual text is in the last child
-        var toggletext = togglelink.get('lastChild');
-
-        var usemodchooser;
-        // Determine whether they're currently hidden
-        if (modchooserlinks.item(0).hasClass('visibleifjs')) {
-            // The modchooser is currently visible, hide it
-            usemodchooser = 0;
-            modchooserlinks
-                .removeClass('visibleifjs')
-                .addClass('hiddenifjs');
-            dropdowns
-                .addClass('visibleifjs')
-                .removeClass('hiddenifjs');
-            toggletext.set('data', M.util.get_string('modchooserenable', 'moodle'));
-            togglelink.set('href', togglelink.get('href').replace('off', 'on'));
-        } else {
-            // The modchooser is currently not visible, show it
-            usemodchooser = 1;
-            modchooserlinks
-                .addClass('visibleifjs')
-                .removeClass('hiddenifjs');
-            dropdowns
-                .removeClass('visibleifjs')
-                .addClass('hiddenifjs');
-            toggletext.set('data', M.util.get_string('modchooserdisable', 'moodle'));
-            togglelink.set('href', togglelink.get('href').replace('on', 'off'));
-        }
-
-        M.util.set_user_preference('usemodchooser', usemodchooser);
-
-        // Prevent the page from reloading
-        e.preventDefault();
-    },
-
     /**
      * Helper function to set the value of a hidden radio button when a
      * selection is made.
index 1101ecf..e4398be 100644 (file)
@@ -126,6 +126,7 @@ $string['componentinstalled'] = 'Component installed';
 $string['computedfromlogs'] = 'Computed from logs since {$a}.';
 $string['condifmodeditdefaults'] = 'Default values are used in the settings form when creating a new activity or resource.';
 $string['confeditorhidebuttons'] = 'Select the buttons that should be hidden in the HTML editor.';
+$string['configenableactivitychooser'] = 'The activity chooser is a dialog box with a short description of each activity and resource. If disabled, separate resource and activity dropdown menus are provided instead.';
 $string['configallcountrycodes'] = 'This is the list of countries that may be selected in various places, for example in a user\'s profile. If blank (the default) the list in countries.php in the standard English language pack is used. That is the list from ISO 3166-1. Otherwise, you can specify a comma-separated list of codes, for example \'GB,FR,ES\'. If you add new, non-standard codes here, you will need to add them to countries.php in \'en\' and your language pack.';
 $string['configallowassign'] = 'You can allow people who have the roles on the left side to assign some of the column roles to other people';
 $string['configallowblockstodock'] = 'If enabled and supported by the selected theme users can choose to move blocks to a special dock.';
@@ -458,6 +459,7 @@ $string['emoticons_desc'] = 'This form defines the emoticons (or smileys) used a
 * Alternative text (optional) - String identifier and component of the alternative text of the emoticon.';
 $string['emoticonsreset'] = 'Reset emoticons setting to default values';
 $string['emptysettingvalue'] = 'Empty';
+$string['enableactivitychooser'] = 'Enable activity chooser';
 $string['enableblogs'] = 'Enable blogs';
 $string['enablecalendarexport'] = 'Enable calendar export';
 $string['enablecomments'] = 'Enable comments';
index 159bc3b..64f618c 100644 (file)
@@ -29,10 +29,12 @@ manageofficialtags,core_tag
 settypeofficial,core_tag
 filetoolarge,core
 maxbytesforfile,core
+modchooserenable,core
+modchooserdisable,core
 maxbytes,core_error
 downloadcsv,core_table
 downloadexcel,core_table
 downloadods,core_table
 downloadoptions,core_table
 downloadtsv,core_table
-downloadxhtml,core_table
+downloadxhtml,core_table
\ No newline at end of file
index 5386298..e3085a1 100644 (file)
@@ -172,11 +172,13 @@ $string['mysqliextensionisnotpresentinphp'] = 'PHP has not been properly configu
 $string['nativemariadb'] = 'MariaDB (native/mariadb)';
 $string['nativemariadbhelp'] = '<p>The database is where most of the Moodle settings and data are stored and must be configured here.</p>
 <p>The database name, username, and password are required fields; table prefix is optional.</p>
+<p>The database name may contain only alphanumeric characters, dollar ($) and underscore (_).</p>
 <p>If the database currently does not exist, and the user you specify has permission, Moodle will attempt to create a new database with the correct permissions and settings.</p>
 <p>This driver is not compatible with legacy MyISAM engine.</p>';
 $string['nativemysqli'] = 'Improved MySQL (native/mysqli)';
 $string['nativemysqlihelp'] = '<p>The database is where most of the Moodle settings and data are stored and must be configured here.</p>
 <p>The database name, username, and password are required fields; table prefix is optional.</p>
+<p>The database name may contain only alphanumeric characters, dollar ($) and underscore (_).</p>
 <p>If the database currently does not exist, and the user you specify has permission, Moodle will attempt to create a new database with the correct permissions and settings.</p>';
 $string['nativemssql'] = 'SQL*Server FreeTDS (native/mssql)';
 $string['nativemssqlhelp'] = 'Now you need to configure the database where most Moodle data will be stored.
index 9d0ac3c..aa19259 100644 (file)
@@ -322,6 +322,7 @@ $string['courseformats'] = 'Course formats';
 $string['courseformatoptions'] = 'Formatting options for {$a}';
 $string['courseformatudpate'] = 'Update format';
 $string['courseprofiles'] = 'Course profiles';
+$string['coursepreferences'] = 'Course preferences';
 $string['coursegrades'] = 'Course grades';
 $string['coursehelpcategory'] = 'Position the course on the course listing and may make it easier for students to find it.';
 $string['coursehelpforce'] = 'Force the course group mode to every activity in the course.';
@@ -1161,8 +1162,6 @@ $string['moodlelogo'] = 'Moodle logo';
 $string['month'] = 'Month';
 $string['months'] = 'Months';
 $string['modified'] = 'Modified';
-$string['modchooserenable'] = 'Activity chooser on';
-$string['modchooserdisable'] = 'Activity chooser off';
 $string['moduleintro'] = 'Description';
 $string['modulesetup'] = 'Setting up module tables';
 $string['modulesuccess'] = '{$a} tables have been set up correctly';
@@ -2027,3 +2026,7 @@ $string['zippingbackup'] = 'Zipping backup';
 // Deprecated since Moodle 3.1.
 $string['filetoolarge'] = 'is too large to upload';
 $string['maxbytesforfile'] = 'The file {$a} is larger than the maximum size allowed.';
+
+// Deprecated since Moodle 3.2.
+$string['modchooserenable'] = 'Activity chooser on';
+$string['modchooserdisable'] = 'Activity chooser off';
\ No newline at end of file
index 6e35cce..083a135 100644 (file)
@@ -4804,6 +4804,9 @@ function remove_course_contents($courseid, $showfeedback = true, array $options
         echo $OUTPUT->notification($strdeleted.get_string('type_block_plural', 'plugin'), 'notifysuccess');
     }
 
+    // Get the list of all modules that are properly installed.
+    $allmodules = $DB->get_records_menu('modules', array(), '', 'name, id');
+
     // Delete every instance of every module,
     // this has to be done before deleting of course level stuff.
     $locations = core_component::get_plugin_list('mod');
@@ -4811,30 +4814,36 @@ function remove_course_contents($courseid, $showfeedback = true, array $options
         if ($modname === 'NEWMODULE') {
             continue;
         }
-        if ($module = $DB->get_record('modules', array('name' => $modname))) {
+        if (array_key_exists($modname, $allmodules)) {
+            $sql = "SELECT cm.*, m.id AS modinstance, m.name, '$modname' AS modname
+              FROM {".$modname."} m
+                   LEFT JOIN {course_modules} cm ON cm.instance = m.id AND cm.module = :moduleid
+             WHERE m.course = :courseid";
+            $instances = $DB->get_records_sql($sql, array('courseid' => $course->id,
+                'modulename' => $modname, 'moduleid' => $allmodules[$modname]));
+
             include_once("$moddir/lib.php");                 // Shows php warning only if plugin defective.
             $moddelete = $modname .'_delete_instance';       // Delete everything connected to an instance.
             $moddeletecourse = $modname .'_delete_course';   // Delete other stray stuff (uncommon).
 
-            if ($instances = $DB->get_records($modname, array('course' => $course->id))) {
-                foreach ($instances as $instance) {
-                    if ($cm = get_coursemodule_from_instance($modname, $instance->id, $course->id)) {
+            if ($instances) {
+                foreach ($instances as $cm) {
+                    if ($cm->id) {
                         // Delete activity context questions and question categories.
                         question_delete_activity($cm,  $showfeedback);
-
                         // Notify the competency subsystem.
                         \core_competency\api::hook_course_module_deleted($cm);
                     }
                     if (function_exists($moddelete)) {
                         // This purges all module data in related tables, extra user prefs, settings, etc.
-                        $moddelete($instance->id);
+                        $moddelete($cm->modinstance);
                     } else {
                         // NOTE: we should not allow installation of modules with missing delete support!
                         debugging("Defective module '$modname' detected when deleting course contents: missing function $moddelete()!");
-                        $DB->delete_records($modname, array('id' => $instance->id));
+                        $DB->delete_records($modname, array('id' => $cm->modinstance));
                     }
 
-                    if ($cm) {
+                    if ($cm->id) {
                         // Delete cm and its context - orphaned contexts are purged in cron in case of any race condition.
                         context_helper::delete_instance(CONTEXT_MODULE, $cm->id);
                         $DB->delete_records('course_modules', array('id' => $cm->id));
@@ -4842,7 +4851,9 @@ function remove_course_contents($courseid, $showfeedback = true, array $options
                 }
             }
             if (function_exists($moddeletecourse)) {
-                // Execute ptional course cleanup callback.
+                // Execute optional course cleanup callback. Deprecated since Moodle 3.2. TODO MDL-53297 remove in 3.6.
+                debugging("Callback delete_course is deprecated. Function $moddeletecourse should be converted " .
+                    'to observer of event \core\event\course_content_deleted', DEBUG_DEVELOPER);
                 $moddeletecourse($course, $showfeedback);
             }
             if ($instances and $showfeedback) {
@@ -4862,12 +4873,13 @@ function remove_course_contents($courseid, $showfeedback = true, array $options
            'coursemoduleid IN (SELECT id from {course_modules} WHERE course=?)',
            array($courseid));
 
-    // Remove course-module data.
+    // Remove course-module data that has not been removed in modules' _delete_instance callbacks.
     $cms = $DB->get_records('course_modules', array('course' => $course->id));
+    $allmodulesbyid = array_flip($allmodules);
     foreach ($cms as $cm) {
-        if ($module = $DB->get_record('modules', array('id' => $cm->module))) {
+        if (array_key_exists($cm->module, $allmodulesbyid)) {
             try {
-                $DB->delete_records($module->name, array('id' => $cm->instance));
+                $DB->delete_records($allmodulesbyid[$cm->module], array('id' => $cm->instance));
             } catch (Exception $e) {
                 // Ignore weird or missing table problems.
             }
@@ -4880,17 +4892,19 @@ function remove_course_contents($courseid, $showfeedback = true, array $options
         echo $OUTPUT->notification($strdeleted.get_string('type_mod_plural', 'plugin'), 'notifysuccess');
     }
 
-    // Cleanup the rest of plugins.
+    // Cleanup the rest of plugins. Deprecated since Moodle 3.2. TODO MDL-53297 remove in 3.6.
     $cleanuplugintypes = array('report', 'coursereport', 'format');
     $callbacks = get_plugins_with_function('delete_course', 'lib.php');
     foreach ($cleanuplugintypes as $type) {
         if (!empty($callbacks[$type])) {
             foreach ($callbacks[$type] as $pluginfunction) {
+                debugging("Callback delete_course is deprecated. Function $pluginfunction should be converted " .
+                    'to observer of event \core\event\course_content_deleted', DEBUG_DEVELOPER);
                 $pluginfunction($course->id, $showfeedback);
             }
-        }
-        if ($showfeedback) {
-            echo $OUTPUT->notification($strdeleted.get_string('type_'.$type.'_plural', 'plugin'), 'notifysuccess');
+            if ($showfeedback) {
+                echo $OUTPUT->notification($strdeleted.get_string('type_'.$type.'_plural', 'plugin'), 'notifysuccess');
+            }
         }
     }
 
index afb15b8..539a410 100644 (file)
@@ -4453,6 +4453,15 @@ class settings_navigation extends navigation_node {
             }
         }
 
+        // Add "Course preferences" link.
+        if (isloggedin() && !isguestuser($user)) {
+            if ($currentuser && has_capability('moodle/user:editownprofile', $systemcontext) ||
+                has_capability('moodle/user:editprofile', $usercontext)) {
+                $url = new moodle_url('/user/course.php', array('id' => $user->id, 'course' => $course->id));
+                $useraccount->add(get_string('coursepreferences'), $url, self::TYPE_SETTING, null, 'coursepreferences');
+            }
+        }
+
         // View the roles settings.
         if (has_any_capability(array('moodle/role:assign', 'moodle/role:safeoverride', 'moodle/role:override',
                 'moodle/role:manage'), $usercontext)) {
index 1303d35..3a365e3 100644 (file)
@@ -279,7 +279,6 @@ ul.assignfeedback_editpdf_menu {
 
 .dir-rtl .assignfeedback_editpdf_widget .commentdrawable a {
     float: left;
-    left: none;
     right: -17px;
     border-left: 0px;
     border-right: 1px solid #ccc;
index 90d7153..2d40ca1 100644 (file)
@@ -1,4 +1,4 @@
-
+/*csslint important:false */
 #page-mod-book-print {
     color: #000;
     background-color: #fff;
index 7c3ba47..2de72fa 100644 (file)
-.path-mod-choice .results {border-collapse: separate;}
-.path-mod-choice .results .data {vertical-align:top;white-space: nowrap;}
-.path-mod-choice .button {text-align:center;}
-.path-mod-choice .attemptcell {width:5px;white-space: nowrap;}
+.path-mod-choice .results {
+  border-collapse: separate;
+}
+
+.path-mod-choice .results .data {
+  vertical-align: top;
+  white-space: nowrap;
+}
+
+.path-mod-choice .button {
+  text-align: center;
+}
+
+.path-mod-choice .attemptcell {
+  width: 5px;
+  white-space: nowrap;
+}
+
 .path-mod-choice .anonymous,
-.path-mod-choice .names {margin-left:auto;margin-right:auto; width:80%;}
-.path-mod-choice .downloadreport {border-width:0;margin-left:10%;}
-.path-mod-choice .choiceresponse {width:100%;}
-.path-mod-choice .choiceresponse .picture {width:10px;white-space: nowrap;}
-.path-mod-choice .choiceresponse .fullname {width:100%;white-space: nowrap;}
+.path-mod-choice .names {
+  margin-left: auto;
+  margin-right: auto;
+  width: 80%;
+}
+
+.path-mod-choice .downloadreport {
+  border-width: 0;
+  margin-left: 10%;
+}
+
+.path-mod-choice .choiceresponse {
+  width: 100%;
+}
+
+.path-mod-choice .choiceresponse .picture {
+  width: 10px;
+  white-space: nowrap;
+}
+
+.path-mod-choice .choiceresponse .fullname {
+  width: 100%;
+  white-space: nowrap;
+}
 
-.path-mod-choice .responseheader {width: 100%; text-align: center; margin-top: 10px;}
-.path-mod-choice .choices .option label {vertical-align: top;}
-.path-mod-choice .choices .option input {vertical-align: middle;}
+.path-mod-choice .responseheader {
+  width: 100%;
+  text-align: center;
+  margin-top: 10px;
+}
+
+.path-mod-choice .choices .option label {
+  vertical-align: top;
+}
+
+.path-mod-choice .choices .option input {
+  vertical-align: middle;
+}
 
 .path-mod-choice .horizontal,
-.path-mod-choice .vertical {margin-left: 10%;margin-right: 10%;}
-.path-mod-choice .horizontal .choices .option {padding-right: 20px; display: inline-block; white-space: normal;}
-.path-mod-choice .horizontal .choices .button {margin-top: 10px;}
-.path-mod-choice ul.choices li {list-style:none;}
-.path-mod-choice .results { text-align: center;}
-.path-mod-choice .results.anonymous .graph.horizontal {vertical-align: middle;text-align: left;width:70%;}
+.path-mod-choice .vertical {
+  margin-left: 10%;
+  margin-right: 10%;
+}
+
+.path-mod-choice .horizontal .choices .option {
+  padding-right: 20px;
+  display: inline-block;
+  white-space: normal;
+}
+
+.path-mod-choice .horizontal .choices .button {
+  margin-top: 10px;
+}
+
+.path-mod-choice ul.choices li {
+  list-style: none;
+}
+
+.path-mod-choice .results {
+  text-align: center;
+}
+
+.path-mod-choice .results.anonymous .graph.horizontal {
+  vertical-align: middle;
+  text-align: left;
+  width: 70%;
+}
 
 .path-mod-choice .results.anonymous .graph.vertical,
-.path-mod-choice .cell {vertical-align: bottom; text-align: center; }
-.path-mod-choice .results.anonymous th.header {border: 1px solid inherit;}
+.path-mod-choice .cell {
+  vertical-align: bottom;
+  text-align: center;
+}
+
+.path-mod-choice .results.names .header {
+  width: 10%;
+  white-space: normal;
+}
+
+.path-mod-choice .results.names .cell {
+  vertical-align: top;
+  text-align: left;
+}
 
-.path-mod-choice .results.names .header{width:10%; white-space: normal;}
-.path-mod-choice .results.names .cell{vertical-align: top; text-align: left;}
 .path-mod-choice .results.names .user,
-.path-mod-choice #yourselection {padding: 5px;}
+.path-mod-choice #yourselection {
+  padding: 5px;
+}
+
 .path-mod-choice .results.names .user .attemptaction,
 .path-mod-choice .results.names .user .image,
-.path-mod-choice .results.names .user .fullname{float:left;}
-.path-mod-choice .results.names .user .fullname{padding-left: 5px;}
-.path-mod-choice .results .data.header {width: 10%;}
-.path-mod-choice .responseaction {text-align: center;}
-.path-mod-choice .results .option {white-space: normal;}
-.path-mod-choice .response {overflow: auto;}
+.path-mod-choice .results.names .user .fullname {
+  float: left;
+}
+
+.path-mod-choice .results.names .user .fullname {
+  padding-left: 5px;
+}
+
+.path-mod-choice .results .data.header {
+  width: 10%;
+}
+
+.path-mod-choice .responseaction {
+  text-align: center;
+}
+
+.path-mod-choice .results .option {
+  white-space: normal;
+}
+
+.path-mod-choice .response {
+  overflow: auto;
+}
+
 .path-mod-choice .results .option,
 .path-mod-choice .results .numberofuser,
-.path-mod-choice .results .percentage {font-weight: bold; font-size: 108%;}
+.path-mod-choice .results .percentage {
+  font-weight: bold;
+  font-size: 108%;
+}
 
-#page-mod-choice-report .downloadreport ul li {list-style:none;padding: 0 20px; display: inline;float: left; }
-.path-mod-choice .clearfloat {float:none; clear:both;}
+#page-mod-choice-report .downloadreport ul li {
+  list-style: none;
+  padding: 0 20px;
+  float: left;
+}
+
+.path-mod-choice .clearfloat {
+  float: none;
+  clear: both;
+}
 
 /**
  * Override for RTL layout
  */
-.path-mod-choice.dir-rtl .horizontal .choices .option {padding-right:0px; padding-left: 20px; float:right;}
-.path-mod-choice.dir-rtl .results.anonymous .graph.horizontal {text-align: right;}
-.path-mod-choice.dir-rtl .results.anonymous { text-align: center; }
-.path-mod-choice.dir-rtl .results.names .cell{text-align: right;}
+.path-mod-choice.dir-rtl .horizontal .choices .option {
+  padding-right: 0px;
+  padding-left: 20px;
+  float: right;
+}
+
+.path-mod-choice.dir-rtl .results.anonymous .graph.horizontal {
+  text-align: right;
+}
+
+.path-mod-choice.dir-rtl .results.anonymous {
+  text-align: center;
+}
+
+.path-mod-choice.dir-rtl .results.names .cell {
+  text-align: right;
+}
+
 .path-mod-choice.dir-rtl .results.names .user .attemptaction,
 .path-mod-choice.dir-rtl .results.names .user .image,
 .path-mod-choice.dir-rtl .results.names .user .fullname,
-.path-mod-choice.dir-rtl .results.names .user .fullname{padding-left: 0px; padding-right: 5px;}
-.path-mod-choice.dir-rtl .downloadreport {margin-left:0;margin-right: 25%;}
+.path-mod-choice.dir-rtl .results.names .user .fullname {
+  padding-left: 0px;
+  padding-right: 5px;
+}
+
+.path-mod-choice.dir-rtl .downloadreport {
+  margin-left: 0;
+  margin-right: 25%;
+}
+
+#page-mod-choice-report.dir-rtl .downloadreport ul li {
+  float: right;
+}
 
-#page-mod-choice-report.dir-rtl .downloadreport ul li{float:right;}
-#page-mod-choice-view.dir-rtl .reportlink {text-align: left;}
+#page-mod-choice-view.dir-rtl .reportlink {
+  text-align: left;
+}
index 7c75522..2841932 100644 (file)
@@ -22,8 +22,8 @@
 
 .picturediv {
   display: inline;
-  width: 150px;
-  height: 200px;
+  max-width: 150px;
+  max-height: 200px;
 }
 
 .inline {
@@ -39,4 +39,4 @@
 #singleimage img {
   width: 700px;
   height: auto;
-}
\ No newline at end of file
+}
diff --git a/mod/feedback/classes/observer.php b/mod/feedback/classes/observer.php
new file mode 100644 (file)
index 0000000..5d5b22b
--- /dev/null
@@ -0,0 +1,46 @@
+<?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/>.
+
+/**
+ * Event observers supported by this module
+ *
+ * @package    mod_feedback
+ * @copyright  2016 Marina Glancy
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+defined('MOODLE_INTERNAL') || die();
+
+/**
+ * Event observers supported by this module
+ *
+ * @package    mod_feedback
+ * @copyright  2016 Marina Glancy
+ * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class mod_feedback_observer {
+
+    /**
+     * Observer for the even course_content_deleted - delete all course templates.
+     *
+     * @param \core\event\course_content_deleted $event
+     */
+    public static function course_content_deleted(\core\event\course_content_deleted $event) {
+        global $DB;
+        // Delete all templates of given course.
+        $DB->delete_records('feedback_template', array('course' => $event->objectid));
+    }
+}
similarity index 57%
rename from course/category.php
rename to mod/feedback/db/events.php
index 89a119d..68baaa8 100644 (file)
 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
 
 /**
- * Displays the top level category or all courses
+ * Feedback event handler definition.
  *
- * @package    core_coure
- * @copyright  1999 onwards Martin Dougiamas  {@link http://moodle.com}
- * @license    http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @package mod_feedback
+ * @category event
+ * @copyright 2016 Marina Glancy
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  */
 
-require_once("../config.php");
+// List of observers.
+$observers = array(
 
-$categoryid = required_param('id', PARAM_INT); // Category id.
+    array(
+        'eventname'   => '\core\event\course_content_deleted',
+        'callback'    => 'mod_feedback_observer::course_content_deleted',
+    ),
 
-debugging('Please use URL /course/index.php?categoryid=XXX instead of /course/category.php?id=XXX', DEBUG_DEVELOPER);
-
-redirect(new moodle_url('/course/index.php', array('categoryid' => $categoryid)));
\ No newline at end of file
+);
index 272b6d5..eff359a 100644 (file)
@@ -312,21 +312,6 @@ function feedback_delete_instance($id) {
     return $DB->delete_records("feedback", array("id"=>$id));
 }
 
-/**
- * this is called after deleting all instances if the course will be deleted.
- * only templates have to be deleted
- *
- * @global object
- * @param object $course
- * @return boolean
- */
-function feedback_delete_course($course) {
-    global $DB;
-
-    //delete all templates of given course
-    return $DB->delete_records('feedback_template', array('course'=>$course->id));
-}
-
 /**
  * Return a small object with summary information about what a
  * user has done with a given particular instance of this module
index a7dcf4c..4d6fe23 100644 (file)
@@ -329,5 +329,18 @@ class mod_feedback_events_testcase extends advanced_testcase {
             $this->assertContains("The 'anonymous' value must be set in other.", $e->getMessage());
         }
     }
+
+    /**
+     * Test that event observer is executed on course deletion and the templates are removed.
+     */
+    public function test_delete_course() {
+        global $DB;
+        $this->resetAfterTest();
+        feedback_save_as_template($this->eventfeedback, 'my template', 0);
+        $courseid = $this->eventcourse->id;
+        $this->assertNotEmpty($DB->get_records('feedback_template', array('course' => $courseid)));
+        delete_course($this->eventcourse, false);
+        $this->assertEmpty($DB->get_records('feedback_template', array('course' => $courseid)));
+    }
 }
 
index 5e98b6b..6b44cf0 100644 (file)
@@ -24,7 +24,7 @@
 
 defined('MOODLE_INTERNAL') || die();
 
-$plugin->version   = 2016052300;       // The current module version (Date: YYYYMMDDXX)
+$plugin->version   = 2016061300;       // The current module version (Date: YYYYMMDDXX)
 $plugin->requires  = 2016051900;    // Requires this Moodle version
 $plugin->component = 'mod_feedback';   // Full name of the plugin (used for diagnostics)
 $plugin->cron      = 0;
index f6fbd54..f235493 100644 (file)
@@ -87,7 +87,6 @@
 #page-mod-forum-discuss .discussioncontrol.exporttoportfolio {text-align:left;}
 #page-mod-forum-discuss .discussioncontrol.displaymode {padding-right:10px;}
 #page-mod-forum-discuss .discussioncontrol.movediscussion {padding-right:10px;}
-#page-mod-forum-discuss .discussioncontrol.movediscussion .movediscussionoption {}
 
 /** Styles for view.php **/
 #page-mod-forum-view .forumaddnew {margin-bottom: 20px;}
index 1e105c4..7590b83 100644 (file)
@@ -274,19 +274,6 @@ function lesson_delete_instance($id) {
     return $lesson->delete();
 }
 
-/**
- * Given a course object, this function will clean up anything that
- * would be leftover after all the instances were deleted
- *
- * @global object
- * @param object $course an object representing the course that is being deleted
- * @param boolean $feedback to specify if the process must output a summary of its work
- * @return boolean
- */
-function lesson_delete_course($course, $feedback=true) {
-    return true;
-}
-
 /**
  * Return a small object with summary information about what a
  * user has done with a given particular instance of this module
index a865799..0db8f86 100644 (file)
@@ -85,7 +85,7 @@
 }
 
 #page-mod-scorm-player #scormpage .scoframe {
-    frameborder: 0;
+    border: 0;
 }
 
 #page-mod-scorm-player #scormpage #scorm_object {
index ad0c75d..74e8d00 100644 (file)
@@ -1,6 +1,10 @@
 This files describes API changes in /mod/* - activity modules,
 information provided here is intended especially for developers.
 
+=== 3.2 ===
+
+* Callback delete_course is deprecated and should be replaced with observer for event \core\event\course_content_deleted
+
 === 3.1 ===
 
 * Old /mod/MODULENAME/pix/icon.gif and enrol/paypal/pix/icon.gif GIF icons have been removed. Please use pix_icon
index e6f06a7..c40886c 100644 (file)
@@ -1,6 +1,9 @@
 This files describes API changes in /report/* - plugins,
 information provided here is intended especially for developers.
 
+=== 3.2 ===
+* Callback delete_course is deprecated and should be replaced with observer for event \core\event\course_content_deleted
+
 === 2.7 ===
 * How to migrate reports accessing table 'log':
   http://docs.moodle.org/dev/Migrating_log_access_in_reports
diff --git a/user/classes/course_form.php b/user/classes/course_form.php
new file mode 100644 (file)
index 0000000..17a7730
--- /dev/null
@@ -0,0 +1,67 @@
+<?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/>.
+
+/**
+ * Form to edit a users course preferences.
+ *
+ * These are stored as columns in the user table, which
+ * is why they are in /user and not /course or /admin.
+ *
+ * @copyright 2016 Joey Andres <jandres@ualberta.ca>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @package core_user
+ */
+
+namespace core_user;
+
+if (!defined('MOODLE_INTERNAL')) {
+    die('Direct access to this script is forbidden.');  // It must be included from a Moodle page.
+}
+
+require_once($CFG->dirroot.'/lib/formslib.php');
+
+/**
+ * Class user_course_form.
+ *
+ * @copyright 2016 Joey Andres <jandres@ualberta.ca>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class course_form extends \moodleform {
+
+    /**
+     * Define the form.
+     */
+    public function definition () {
+        global $COURSE;
+
+        $mform = $this->_form;
+
+        $mform->addElement('advcheckbox',
+            'enableactivitychooser',
+            get_string('enableactivitychooser', 'admin'),
+            get_string('configenableactivitychooser', 'admin'));
+        $mform->setDefault('enableactivitychooser',
+            get_user_preferences('usemodchooser', true, $this->_customdata['userid']));
+
+        // Add some extra hidden fields.
+        $mform->addElement('hidden', 'id');
+        $mform->setType('id', PARAM_INT);
+        $mform->addElement('hidden', 'course', $COURSE->id);
+        $mform->setType('course', PARAM_INT);
+
+        $this->add_action_buttons(true, get_string('savechanges'));
+    }
+}
\ No newline at end of file
diff --git a/user/course.php b/user/course.php
new file mode 100644 (file)
index 0000000..d0e571b
--- /dev/null
@@ -0,0 +1,65 @@
+<?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/>.
+
+/**
+ * Allows you to edit course preference.
+ *
+ * @copyright 2016 Joey Andres  <jandres@ualberta.ca>
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ * @package core_user
+ */
+
+require_once(__DIR__ . "/../config.php");
+require_once($CFG->dirroot.'/user/editlib.php');
+
+$userid = optional_param('id', $USER->id, PARAM_INT);    // User id.
+$courseid = optional_param('course', SITEID, PARAM_INT);   // Course id (defaults to Site).
+
+$PAGE->set_url('/user/course.php', array('id' => $userid, 'course' => $courseid));
+
+list($user, $course) = useredit_setup_preference_page($userid, $courseid);
+
+// Create form.
+$courseform = new core_user\course_form(null, array('userid' => $user->id));
+
+$courseform->set_data($user);
+
+$redirect = new moodle_url("/user/preferences.php", array('userid' => $user->id));
+if ($courseform->is_cancelled()) {
+    redirect($redirect);
+} else if ($data = $courseform->get_data()) {
+    set_user_preference('usemodchooser', $data->enableactivitychooser, $user);
+
+    redirect($redirect);
+}
+
+// Display page header.
+$streditmycourse = get_string('coursepreferences');
+$userfullname = fullname($user, true);
+
+$PAGE->navbar->includesettingsbase = true;
+
+$PAGE->set_title("$course->shortname: $streditmycourse");
+$PAGE->set_heading($userfullname);
+
+echo $OUTPUT->header();
+echo $OUTPUT->heading($streditmycourse);
+
+// Finally display THE form.
+$courseform->display();
+
+// And proper footer.
+echo $OUTPUT->footer();
diff --git a/user/tests/behat/course_preference.feature b/user/tests/behat/course_preference.feature
new file mode 100644 (file)
index 0000000..7ad8e59
--- /dev/null
@@ -0,0 +1,36 @@
+@core @core_user
+Feature: As a user, "Course preferences" allows me to set my course preference(s).
+  Background:
+    Given I log in as "admin"
+    And the following "courses" exist:
+      | fullname | shortname | format |
+      | Course 1 | C1 | topics |
+    And the following "course enrolments" exist:
+      | user | course | role |
+      | admin | C1 | editingteacher |
+    And I am on site homepage
+    And I follow "Preferences" in the user menu
+    And I follow "Course preferences"
+
+  @javascript
+  Scenario: As a user, "activity chooser" should be the default.
+    # See that the "activity chooser" is enabled by default.
+    Given the field "enableactivitychooser" matches value "1"
+    # See that the "activity chooser" is actually shown by default in course page.
+    When I am on homepage
+    And I follow "Course 1"
+    And I should not see "Add an activity or resource" in the "Topic 1" "section"
+    And I turn editing mode on
+    Then I should see "Add an activity or resource" in the "Topic 1" "section"
+    And I should not see "Add a resource..." in the "Topic 1" "section"
+
+  @javascript
+  Scenario: As a user, "activity chooser" should be disabled when I uncheck it in "Course preferences"
+    Given I set the field "enableactivitychooser" to "0"
+    And I press "Save changes"
+    When I am on homepage
+    And I follow "Course 1"
+    And I should not see "Add a resource..." in the "Topic 1" "section"
+    And I turn editing mode on
+    Then I should see "Add a resource..." in the "Topic 1" "section"
+    And I should not see "Add an activity or resource" in the "Topic 1" "section"
\ No newline at end of file