/**
* For a given course section, marks it visible or hidden,
* and does the same for every activity in that section
+ *
+ * @param int $courseid course id
+ * @param int $sectionnumber The section number to adjust
+ * @param int $visibility The new visibility
+ * @return array A list of resources which were hidden in the section
*/
function set_section_visible($courseid, $sectionnumber, $visibility) {
global $DB;
+ $resourcestotoggle = array();
if ($section = $DB->get_record("course_sections", array("course"=>$courseid, "section"=>$sectionnumber))) {
$DB->set_field("course_sections", "visible", "$visibility", array("id"=>$section->id));
if (!empty($section->sequence)) {
}
}
rebuild_course_cache($courseid);
+
+ // Determine which modules are visible for AJAX update
+ if (!empty($modules)) {
+ list($insql, $params) = $DB->get_in_or_equal($modules);
+ $select = 'id ' . $insql . ' AND visible = ?';
+ array_push($params, $visibility);
+ if (!$visibility) {
+ $select .= ' AND visibleold = 1';
+ }
+ $resourcestotoggle = $DB->get_fieldset_select('course_modules', 'id', $select, $params);
+ }
}
+ return $resourcestotoggle;
}
/**
// very quick on an empty table)
$DB->delete_records('course_modules_completion', array('coursemoduleid' => $cm->id));
$DB->delete_records('course_modules_availability', array('coursemoduleid'=> $cm->id));
+ $DB->delete_records('course_completion_criteria', array('moduleinstance' => $cm->id,
+ 'criteriatype' => COMPLETION_CRITERIA_TYPE_ACTIVITY));
delete_context(CONTEXT_MODULE, $cm->id);
return $DB->delete_records('course_modules', array('id'=>$cm->id));
return false;
}
- $DB->set_field("course_sections", "section", $sectiondest, array("id"=>$sectionrecord->id));
+ // Three-step change ensures that the section always remains unique (there is
+ // a unique index now)
+ $DB->set_field("course_sections", "section", -$sectiondest, array("id"=>$sectionrecord->id));
$DB->set_field("course_sections", "section", $section, array("id"=>$sectiondestrecord->id));
+ $DB->set_field("course_sections", "section", $sectiondest, array("id"=>$sectionrecord->id));
// Update highlighting if the move affects highlighted section
if ($course->marker == $section) {
course_set_display($course->id, $sectiondest);
}
- // Check for duplicates and fix order if needed.
- // There is a very rare case that some sections in the same course have the same section id.
+ // Fix order if needed. The database prevents duplicate sections, but it is
+ // possible there could be a gap in the numbering.
$sections = $DB->get_records('course_sections', array('course'=>$course->id), 'section ASC');
$n = 0;
foreach ($sections as $section) {
return false;
}
- $sections = reorder_sections($sections, $section, $destination);
+ $movedsections = reorder_sections($sections, $section, $destination);
- // Update all sections
- foreach ($sections as $id => $position) {
- $DB->set_field('course_sections', 'section', $position, array('id' => $id));
+ // Update all sections. Do this in 2 steps to avoid breaking database
+ // uniqueness constraint
+ $transaction = $DB->start_delegated_transaction();
+ foreach ($movedsections as $id => $position) {
+ if ($sections[$id] !== $position) {
+ $DB->set_field('course_sections', 'section', -$position, array('id' => $id));
+ }
+ }
+ foreach ($movedsections as $id => $position) {
+ if ($sections[$id] !== $position) {
+ $DB->set_field('course_sections', 'section', $position, array('id' => $id));
+ }
+ }
+
+ // Adjust destination to reflect the actual section
+ $moveup = false;
+ if ($section > $destination) {
+ $destination++;
+ $moveup = true;
+ }
+
+ // If we move the highlighted section itself, then just highlight the destination.
+ // Adjust the higlighted section location if we move something over it either direction.
+ if ($section == $course->marker) {
+ course_set_marker($course, $destination);
+ } elseif ($moveup && $section > $course->marker && $course->marker >= $destination) {
+ course_set_marker($course, $course->marker+1);
+ } elseif (!$moveup && $section < $course->marker && $course->marker <= $destination) {
+ course_set_marker($course, $course->marker-1);
}
// if the focus is on the section that is being moved, then move the focus along
if (course_get_display($course->id) == $section) {
course_set_display($course->id, $destination);
}
+ $transaction->allow_commit();
return true;
}
);
}
}
+
+/**
+ * Include the relevant javascript and language strings for the resource
+ * toolbox YUI module
+ *
+ * @param integer $id The ID of the course being applied to
+ * @param array $modules An array containing the names of the modules in
+ * use on the page
+ * @param object $config An object containing configuration parameters for ajax modules including:
+ * * resourceurl The URL to post changes to for resource changes
+ * * sectionurl The URL to post changes to for section changes
+ * * pageparams Additional parameters to pass through in the post
+ * @return void
+ */
+function include_course_ajax($course, $modules = array(), $config = null) {
+ global $PAGE, $CFG, $USER;
+
+ // Ensure that ajax should be included
+ $courseformatajaxsupport = course_format_ajax_support($course->format);
+ if (!$CFG->enablecourseajax
+ || !$PAGE->theme->enablecourseajax
+ || !$CFG->enableajax
+ || empty($USER->editing)
+ || !$PAGE->user_is_editing()
+ || ($course->id != SITEID && !$courseformatajaxsupport->capable)) {
+ return;
+ }
+
+ if (!$config) {
+ $config = new stdClass();
+ }
+
+ // The URL to use for resource changes
+ if (!isset($config->resourceurl)) {
+ $config->resourceurl = '/course/rest.php';
+ }
+
+ // The URL to use for section changes
+ if (!isset($config->sectionurl)) {
+ $config->sectionurl = '/course/rest.php';
+ }
+
+ // Any additional parameters which need to be included on page submission
+ if (!isset($config->pageparams)) {
+ $config->pageparams = array();
+ }
+
+ // Include toolboxes
+ $PAGE->requires->yui_module('moodle-course-toolboxes',
+ 'M.course.init_resource_toolbox',
+ array(array(
+ 'courseid' => $course->id,
+ 'ajaxurl' => $config->resourceurl,
+ 'config' => $config,
+ ))
+ );
+ $PAGE->requires->yui_module('moodle-course-toolboxes',
+ 'M.course.init_section_toolbox',
+ array(array(
+ 'courseid' => $course->id,
+ 'format' => $course->format,
+ 'ajaxurl' => $config->sectionurl,
+ 'config' => $config,
+ ))
+ );
+
+ // Include course dragdrop
+ if ($course->id != SITEID) {
+ $PAGE->requires->yui_module('moodle-course-dragdrop', 'M.core_course.init_section_dragdrop',
+ array(array(
+ 'courseid' => $course->id,
+ 'ajaxurl' => $config->sectionurl,
+ 'config' => $config,
+ )), null, true);
+
+ $PAGE->requires->yui_module('moodle-course-dragdrop', 'M.core_course.init_resource_dragdrop',
+ array(array(
+ 'courseid' => $course->id,
+ 'ajaxurl' => $config->resourceurl,
+ 'config' => $config,
+ )), null, true);
+ }
+
+ // Include blocks dragdrop
+ $params = array(
+ 'courseid' => $course->id,
+ 'pagetype' => $PAGE->pagetype,
+ 'pagelayout' => $PAGE->pagelayout,
+ 'regions' => $PAGE->blocks->get_regions(),
+ );
+ $PAGE->requires->yui_module('moodle-core-blocks', 'M.core_blocks.init_dragdrop', array($params), null, true);
+
+ // Require various strings for the command toolbox
+ $PAGE->requires->strings_for_js(array(
+ 'moveleft',
+ 'deletechecktype',
+ 'deletechecktypename',
+ 'show',
+ 'hide',
+ 'groupsnone',
+ 'groupsvisible',
+ 'groupsseparate',
+ 'clicktochangeinbrackets',
+ 'markthistopic',
+ 'markedthistopic',
+ 'move',
+ 'movesection',
+ ), 'moodle');
+
+ // Include format-specific strings
+ if ($course->id != SITEID) {
+ $PAGE->requires->strings_for_js(array(
+ 'showfromothers',
+ 'hidefromothers',
+ ), 'format_' . $course->format);
+ }
+
+ // For confirming resource deletion we need the name of the module in question
+ foreach ($modules as $module => $modname) {
+ $PAGE->requires->string_for_js('pluginname', $module);
+ }
+}