mirror of
https://github.com/moodle/moodle.git
synced 2025-01-18 05:58:34 +01:00
MDL-51802 course: allow to edit section names on the course page
This commit is contained in:
parent
cdc5f9785b
commit
f26481c2dc
@ -114,28 +114,7 @@ if ($mform->is_cancelled()){
|
||||
$data->availability = null;
|
||||
}
|
||||
}
|
||||
$DB->update_record('course_sections', $data);
|
||||
rebuild_course_cache($course->id, true);
|
||||
if (isset($data->section)) {
|
||||
// Usually edit form does not change relative section number but just in case.
|
||||
$sectionnum = $data->section;
|
||||
}
|
||||
course_get_format($course->id)->update_section_format_options($data);
|
||||
|
||||
// Set section info, as this might not be present in form_data.
|
||||
if (!isset($data->section)) {
|
||||
$data->section = $sectionnum;
|
||||
}
|
||||
// Trigger an event for course section update.
|
||||
$event = \core\event\course_section_updated::create(
|
||||
array(
|
||||
'objectid' => $data->id,
|
||||
'courseid' => $course->id,
|
||||
'context' => $context,
|
||||
'other' => array('sectionnum' => $data->section)
|
||||
)
|
||||
);
|
||||
$event->trigger();
|
||||
course_update_section($course, $section, $data);
|
||||
|
||||
$PAGE->navigation->clear_cache();
|
||||
redirect(course_get_url($course, $section, array('sr' => $sectionreturn)));
|
||||
|
@ -1030,6 +1030,76 @@ abstract class format_base {
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the templateable object to display section name
|
||||
*
|
||||
* @param \section_info|\stdClass $section
|
||||
* @param bool $linkifneeded
|
||||
* @param bool $editable
|
||||
* @param null|lang_string|string $edithint
|
||||
* @param null|lang_string|string $editlabel
|
||||
* @return \core\output\inplace_editable
|
||||
*/
|
||||
public function inplace_editable_render_section_name($section, $linkifneeded = true,
|
||||
$editable = null, $edithint = null, $editlabel = null) {
|
||||
global $USER, $CFG;
|
||||
require_once($CFG->dirroot.'/course/lib.php');
|
||||
|
||||
if ($editable === null) {
|
||||
$editable = !empty($USER->editing) && has_capability('moodle/course:update',
|
||||
context_course::instance($section->course));
|
||||
}
|
||||
|
||||
$displayvalue = $title = get_section_name($section->course, $section);
|
||||
if ($linkifneeded) {
|
||||
// Display link under the section name if the course format setting is to display one section per page.
|
||||
$url = course_get_url($section->course, $section->section, array('navigation' => true));
|
||||
if ($url) {
|
||||
$displayvalue = html_writer::link($url, $title);
|
||||
}
|
||||
$itemtype = 'sectionname';
|
||||
} else {
|
||||
// If $linkifneeded==false, we never display the link (this is used when rendering the section header).
|
||||
// Itemtype 'sectionnamenl' (nl=no link) will tell the callback that link should not be rendered -
|
||||
// there is no other way callback can know where we display the section name.
|
||||
$itemtype = 'sectionnamenl';
|
||||
}
|
||||
if (empty($edithint)) {
|
||||
$edithint = new lang_string('editsectionname');
|
||||
}
|
||||
if (empty($editlabel)) {
|
||||
$editlabel = new lang_string('newsectionname', '', $title);
|
||||
}
|
||||
|
||||
return new \core\output\inplace_editable('format_' . $this->format, $itemtype, $section->id, $editable,
|
||||
$displayvalue, $section->name, $edithint, $editlabel);
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the value in the database and modifies this object respectively.
|
||||
*
|
||||
* ALWAYS check user permissions before performing an update! Throw exceptions if permissions are not sufficient
|
||||
* or value is not legit.
|
||||
*
|
||||
* @param stdClass $section
|
||||
* @param string $itemtype
|
||||
* @param mixed $newvalue
|
||||
* @return \core\output\inplace_editable
|
||||
*/
|
||||
public function inplace_editable_update_section_name($section, $itemtype, $newvalue) {
|
||||
if ($itemtype === 'sectionname' || $itemtype === 'sectionnamenl') {
|
||||
require_login($section->course, false, null, true, true);
|
||||
$context = context_course::instance($section->course);
|
||||
require_capability('moodle/course:update', $context);
|
||||
|
||||
$newtitle = clean_param($newvalue, PARAM_TEXT);
|
||||
if (strval($section->name) !== strval($newtitle)) {
|
||||
course_update_section($section->course, $section, array('name' => $newtitle));
|
||||
}
|
||||
return $this->inplace_editable_render_section_name($section, ($itemtype === 'sectionname'), true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -71,7 +71,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
|
||||
abstract protected function page_title();
|
||||
|
||||
/**
|
||||
* Generate the section title
|
||||
* Generate the section title, wraps it in a link to the section page if page is to be displayed on a separate page
|
||||
*
|
||||
* @param stdClass $section The course_section entry from DB
|
||||
* @param stdClass $course The course entry from DB
|
||||
@ -86,6 +86,17 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the section title to be displayed on the section page, without a link
|
||||
*
|
||||
* @param stdClass $section The course_section entry from DB
|
||||
* @param stdClass $course The course entry from DB
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
public function section_title_without_link($section, $course) {
|
||||
return get_section_name($course, $section);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the edit control action menu
|
||||
*
|
||||
@ -193,7 +204,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
|
||||
'aria-label'=> get_section_name($course, $section)));
|
||||
|
||||
// Create a span that contains the section title to be used to create the keyboard section move menu.
|
||||
$o .= html_writer::tag('span', $this->section_title($section, $course), array('class' => 'hidden sectionname'));
|
||||
$o .= html_writer::tag('span', get_section_name($course, $section), array('class' => 'hidden sectionname'));
|
||||
|
||||
$leftcontent = $this->section_left_content($section, $course, $onsectionpage);
|
||||
$o.= html_writer::tag('div', $leftcontent, array('class' => 'left side'));
|
||||
@ -788,7 +799,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base {
|
||||
if (!$thissection->visible) {
|
||||
$classes .= ' dimmed_text';
|
||||
}
|
||||
$sectionname = html_writer::tag('span', get_section_name($course, $displaysection));
|
||||
$sectionname = html_writer::tag('span', $this->section_title_without_link($thissection, $course));
|
||||
$sectiontitle .= $this->output->heading($sectionname, 3, $classes);
|
||||
|
||||
$sectiontitle .= html_writer::end_tag('div');
|
||||
|
@ -25,7 +25,9 @@
|
||||
|
||||
$string['currentsection'] = 'This topic';
|
||||
$string['editsection'] = 'Edit topic';
|
||||
$string['editsectionname'] = 'Edit topic name';
|
||||
$string['deletesection'] = 'Delete topic';
|
||||
$string['newsectionname'] = 'New name for topic {$a}';
|
||||
$string['sectionname'] = 'Topic';
|
||||
$string['pluginname'] = 'Topics format';
|
||||
$string['section0name'] = 'General';
|
||||
|
@ -382,4 +382,45 @@ class format_topics extends format_base {
|
||||
public function can_delete_section($section) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the templateable object to display section name
|
||||
*
|
||||
* @param \section_info|\stdClass $section
|
||||
* @param bool $linkifneeded
|
||||
* @param bool $editable
|
||||
* @param null|lang_string|string $edithint
|
||||
* @param null|lang_string|string $editlabel
|
||||
* @return \core\output\inplace_editable
|
||||
*/
|
||||
public function inplace_editable_render_section_name($section, $linkifneeded = true,
|
||||
$editable = null, $edithint = null, $editlabel = null) {
|
||||
if (empty($edithint)) {
|
||||
$edithint = new lang_string('editsectionname', 'format_topics');
|
||||
}
|
||||
if (empty($editlabel)) {
|
||||
$title = get_section_name($section->course, $section);
|
||||
$editlabel = new lang_string('newsectionname', 'format_topics', $title);
|
||||
}
|
||||
return parent::inplace_editable_render_section_name($section, $linkifneeded, $editable, $edithint, $editlabel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements callback inplace_editable() allowing to edit values in-place
|
||||
*
|
||||
* @param string $itemtype
|
||||
* @param int $itemid
|
||||
* @param mixed $newvalue
|
||||
* @return \core\output\inplace_editable
|
||||
*/
|
||||
function format_topics_inplace_editable($itemtype, $itemid, $newvalue) {
|
||||
global $DB, $CFG;
|
||||
require_once($CFG->dirroot . '/course/lib.php');
|
||||
if ($itemtype === 'sectionname' || $itemtype === 'sectionnamenl') {
|
||||
$section = $DB->get_record_sql(
|
||||
'SELECT s.* FROM {course_sections} s JOIN {course} c ON s.course = c.id WHERE s.id = ? AND c.format = ?',
|
||||
array($itemid, 'topics'), MUST_EXIST);
|
||||
return course_get_format($section->course)->inplace_editable_update_section_name($section, $itemtype, $newvalue);
|
||||
}
|
||||
}
|
||||
|
@ -73,6 +73,28 @@ class format_topics_renderer extends format_section_renderer_base {
|
||||
return get_string('topicoutline');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the section title, wraps it in a link to the section page if page is to be displayed on a separate page
|
||||
*
|
||||
* @param stdClass $section The course_section entry from DB
|
||||
* @param stdClass $course The course entry from DB
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
public function section_title($section, $course) {
|
||||
return $this->render(course_get_format($course)->inplace_editable_render_section_name($section));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the section title to be displayed on the section page, without a link
|
||||
*
|
||||
* @param stdClass $section The course_section entry from DB
|
||||
* @param stdClass $course The course entry from DB
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
public function section_title_without_link($section, $course) {
|
||||
return $this->render(course_get_format($course)->inplace_editable_render_section_name($section, false));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the edit control items of a section
|
||||
*
|
||||
|
@ -56,6 +56,18 @@ Feature: Sections can be edited and deleted in topics format
|
||||
Then I should see "This is the second topic" in the "li#section-2" "css_element"
|
||||
And I should not see "Topic 2" in the "li#section-2" "css_element"
|
||||
|
||||
@javascript
|
||||
Scenario: Inline edit section name in topics format
|
||||
When I click on "Edit topic name" "link" in the "li#section-1" "css_element"
|
||||
And I set the field "New name for topic Topic 1" to "Midterm evaluation"
|
||||
And I press key "13" in the field "New name for topic Topic 1"
|
||||
Then I should not see "Topic 1" in the "#region-main" "css_element"
|
||||
And "New name for topic" "field" should not exist
|
||||
And I should see "Midterm evaluation" in the "li#section-1" "css_element"
|
||||
And I follow "Course 1"
|
||||
And I should not see "Topic 1" in the "#region-main" "css_element"
|
||||
And I should see "Midterm evaluation" in the "li#section-1" "css_element"
|
||||
|
||||
Scenario: Deleting the last section in topics format
|
||||
When I delete section "5"
|
||||
Then I should see "Are you absolutely sure you want to completely delete \"Topic 5\" and all the activities it contains?"
|
||||
|
@ -146,4 +146,69 @@ class format_topics_testcase extends advanced_testcase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test web service updating section name
|
||||
*/
|
||||
public function test_update_inplace_editable() {
|
||||
global $CFG, $DB, $PAGE;
|
||||
require_once($CFG->dirroot . '/lib/external/externallib.php');
|
||||
|
||||
$this->resetAfterTest();
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$this->setUser($user);
|
||||
$course = $this->getDataGenerator()->create_course(array('numsections' => 5, 'format' => 'topics'),
|
||||
array('createsections' => true));
|
||||
$section = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 2));
|
||||
|
||||
// Call webservice without necessary permissions.
|
||||
try {
|
||||
core_external::update_inplace_editable('format_topics', 'sectionname', $section->id, 'New section name');
|
||||
$this->fail('Exception expected');
|
||||
} catch (moodle_exception $e) {
|
||||
$this->assertEquals('Course or activity not accessible. (Not enrolled)',
|
||||
$e->getMessage());
|
||||
}
|
||||
|
||||
// Change to teacher and make sure that section name can be updated using web service update_inplace_editable().
|
||||
$teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
|
||||
$this->getDataGenerator()->enrol_user($user->id, $course->id, $teacherrole->id);
|
||||
|
||||
$res = core_external::update_inplace_editable('format_topics', 'sectionname', $section->id, 'New section name');
|
||||
$res = external_api::clean_returnvalue(core_external::update_inplace_editable_returns(), $res);
|
||||
$this->assertEquals('New section name', $res['value']);
|
||||
$this->assertEquals('New section name', $DB->get_field('course_sections', 'name', array('id' => $section->id)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test callback updating section name
|
||||
*/
|
||||
public function test_inplace_editable() {
|
||||
global $DB, $PAGE;
|
||||
|
||||
$this->resetAfterTest();
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$course = $this->getDataGenerator()->create_course(array('numsections' => 5, 'format' => 'topics'),
|
||||
array('createsections' => true));
|
||||
$teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
|
||||
$this->getDataGenerator()->enrol_user($user->id, $course->id, $teacherrole->id);
|
||||
$this->setUser($user);
|
||||
|
||||
$section = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 2));
|
||||
|
||||
// Call callback format_topics_inplace_editable() directly.
|
||||
$tmpl = component_callback('format_topics', 'inplace_editable', array('sectionname', $section->id, 'Rename me again'));
|
||||
$this->assertInstanceOf('core\output\inplace_editable', $tmpl);
|
||||
$res = $tmpl->export_for_template($PAGE->get_renderer('core'));
|
||||
$this->assertEquals('Rename me again', $res['value']);
|
||||
$this->assertEquals('Rename me again', $DB->get_field('course_sections', 'name', array('id' => $section->id)));
|
||||
|
||||
// Try updating using callback from mismatching course format.
|
||||
try {
|
||||
$tmpl = component_callback('format_weeks', 'inplace_editable', array('sectionname', $section->id, 'New name'));
|
||||
$this->fail('Exception expected');
|
||||
} catch (moodle_exception $e) {
|
||||
$this->assertEquals(1, preg_match('/^Can not find data record in database/', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,6 +2,10 @@ This files describes API changes for course formats
|
||||
|
||||
Overview of this plugin type at http://docs.moodle.org/dev/Course_formats
|
||||
|
||||
=== 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.
|
||||
|
||||
=== 3.0 ===
|
||||
* Course formats should now use section_edit_control_items and use the returned array of controls items and their attributes to create a
|
||||
renderable menu or array of links. Plugin calls to section_edit_controls will now include the section edit control in the returned array.
|
||||
|
@ -25,7 +25,9 @@
|
||||
|
||||
$string['currentsection'] = 'This week';
|
||||
$string['editsection'] = 'Edit week';
|
||||
$string['editsectionname'] = 'Edit week name';
|
||||
$string['deletesection'] = 'Delete week';
|
||||
$string['newsectionname'] = 'New name for week {$a}';
|
||||
$string['sectionname'] = 'Week';
|
||||
$string['pluginname'] = 'Weekly format';
|
||||
$string['section0name'] = 'General';
|
||||
|
@ -432,4 +432,45 @@ class format_weeks extends format_base {
|
||||
public function can_delete_section($section) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the templateable object to display section name
|
||||
*
|
||||
* @param \section_info|\stdClass $section
|
||||
* @param bool $linkifneeded
|
||||
* @param bool $editable
|
||||
* @param null|lang_string|string $edithint
|
||||
* @param null|lang_string|string $editlabel
|
||||
* @return \core\output\inplace_editable
|
||||
*/
|
||||
public function inplace_editable_render_section_name($section, $linkifneeded = true,
|
||||
$editable = null, $edithint = null, $editlabel = null) {
|
||||
if (empty($edithint)) {
|
||||
$edithint = new lang_string('editsectionname', 'format_weeks');
|
||||
}
|
||||
if (empty($editlabel)) {
|
||||
$title = get_section_name($section->course, $section);
|
||||
$editlabel = new lang_string('newsectionname', 'format_weeks', $title);
|
||||
}
|
||||
return parent::inplace_editable_render_section_name($section, $linkifneeded, $editable, $edithint, $editlabel);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements callback inplace_editable() allowing to edit values in-place
|
||||
*
|
||||
* @param string $itemtype
|
||||
* @param int $itemid
|
||||
* @param mixed $newvalue
|
||||
* @return \core\output\inplace_editable
|
||||
*/
|
||||
function format_weeks_inplace_editable($itemtype, $itemid, $newvalue) {
|
||||
global $DB, $CFG;
|
||||
require_once($CFG->dirroot . '/course/lib.php');
|
||||
if ($itemtype === 'sectionname' || $itemtype === 'sectionnamenl') {
|
||||
$section = $DB->get_record_sql(
|
||||
'SELECT s.* FROM {course_sections} s JOIN {course} c ON s.course = c.id WHERE s.id = ? AND c.format = ?',
|
||||
array($itemid, 'weeks'), MUST_EXIST);
|
||||
return course_get_format($section->course)->inplace_editable_update_section_name($section, $itemtype, $newvalue);
|
||||
}
|
||||
}
|
||||
|
@ -59,4 +59,26 @@ class format_weeks_renderer extends format_section_renderer_base {
|
||||
protected function page_title() {
|
||||
return get_string('weeklyoutline');
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the section title, wraps it in a link to the section page if page is to be displayed on a separate page
|
||||
*
|
||||
* @param stdClass $section The course_section entry from DB
|
||||
* @param stdClass $course The course entry from DB
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
public function section_title($section, $course) {
|
||||
return $this->render(course_get_format($course)->inplace_editable_render_section_name($section));
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate the section title to be displayed on the section page, without a link
|
||||
*
|
||||
* @param stdClass $section The course_section entry from DB
|
||||
* @param stdClass $course The course entry from DB
|
||||
* @return string HTML to output.
|
||||
*/
|
||||
public function section_title_without_link($section, $course) {
|
||||
return $this->render(course_get_format($course)->inplace_editable_render_section_name($section, false));
|
||||
}
|
||||
}
|
||||
|
@ -57,6 +57,18 @@ Feature: Sections can be edited and deleted in weeks format
|
||||
Then I should see "This is the second week" in the "li#section-2" "css_element"
|
||||
And I should not see "8 May - 14 May" in the "li#section-2" "css_element"
|
||||
|
||||
@javascript
|
||||
Scenario: Inline edit section name in weeks format
|
||||
When I click on "Edit week name" "link" in the "li#section-1" "css_element"
|
||||
And I set the field "New name for week 1 May - 7 May" to "Midterm evaluation"
|
||||
And I press key "13" in the field "New name for week 1 May - 7 May"
|
||||
Then I should not see "1 May - 7 May" in the "#region-main" "css_element"
|
||||
And "New name for week" "field" should not exist
|
||||
And I should see "Midterm evaluation" in the "li#section-1" "css_element"
|
||||
And I follow "Course 1"
|
||||
And I should not see "1 May - 7 May" in the "#region-main" "css_element"
|
||||
And I should see "Midterm evaluation" in the "li#section-1" "css_element"
|
||||
|
||||
Scenario: Deleting the last section in weeks format
|
||||
Given I should see "29 May - 4 June" in the "li#section-5" "css_element"
|
||||
When I delete section "5"
|
||||
|
@ -152,4 +152,69 @@ class format_weeks_testcase extends advanced_testcase {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test web service updating section name
|
||||
*/
|
||||
public function test_update_inplace_editable() {
|
||||
global $CFG, $DB, $PAGE;
|
||||
require_once($CFG->dirroot . '/lib/external/externallib.php');
|
||||
|
||||
$this->resetAfterTest();
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$this->setUser($user);
|
||||
$course = $this->getDataGenerator()->create_course(array('numsections' => 5, 'format' => 'weeks'),
|
||||
array('createsections' => true));
|
||||
$section = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 2));
|
||||
|
||||
// Call webservice without necessary permissions.
|
||||
try {
|
||||
core_external::update_inplace_editable('format_weeks', 'sectionname', $section->id, 'New section name');
|
||||
$this->fail('Exception expected');
|
||||
} catch (moodle_exception $e) {
|
||||
$this->assertEquals('Course or activity not accessible. (Not enrolled)',
|
||||
$e->getMessage());
|
||||
}
|
||||
|
||||
// Change to teacher and make sure that section name can be updated using web service update_inplace_editable().
|
||||
$teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
|
||||
$this->getDataGenerator()->enrol_user($user->id, $course->id, $teacherrole->id);
|
||||
|
||||
$res = core_external::update_inplace_editable('format_weeks', 'sectionname', $section->id, 'New section name');
|
||||
$res = external_api::clean_returnvalue(core_external::update_inplace_editable_returns(), $res);
|
||||
$this->assertEquals('New section name', $res['value']);
|
||||
$this->assertEquals('New section name', $DB->get_field('course_sections', 'name', array('id' => $section->id)));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test callback updating section name
|
||||
*/
|
||||
public function test_inplace_editable() {
|
||||
global $CFG, $DB, $PAGE;
|
||||
|
||||
$this->resetAfterTest();
|
||||
$user = $this->getDataGenerator()->create_user();
|
||||
$course = $this->getDataGenerator()->create_course(array('numsections' => 5, 'format' => 'weeks'),
|
||||
array('createsections' => true));
|
||||
$teacherrole = $DB->get_record('role', array('shortname' => 'editingteacher'));
|
||||
$this->getDataGenerator()->enrol_user($user->id, $course->id, $teacherrole->id);
|
||||
$this->setUser($user);
|
||||
|
||||
$section = $DB->get_record('course_sections', array('course' => $course->id, 'section' => 2));
|
||||
|
||||
// Call callback format_weeks_inplace_editable() directly.
|
||||
$tmpl = component_callback('format_weeks', 'inplace_editable', array('sectionname', $section->id, 'Rename me again'));
|
||||
$this->assertInstanceOf('core\output\inplace_editable', $tmpl);
|
||||
$res = $tmpl->export_for_template($PAGE->get_renderer('core'));
|
||||
$this->assertEquals('Rename me again', $res['value']);
|
||||
$this->assertEquals('Rename me again', $DB->get_field('course_sections', 'name', array('id' => $section->id)));
|
||||
|
||||
// Try updating using callback from mismatching course format.
|
||||
try {
|
||||
$tmpl = component_callback('format_topics', 'inplace_editable', array('sectionname', $section->id, 'New name'));
|
||||
$this->fail('Exception expected');
|
||||
} catch (moodle_exception $e) {
|
||||
$this->assertEquals(1, preg_match('/^Can not find data record in database/', $e->getMessage()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1198,37 +1198,10 @@ function set_section_visible($courseid, $sectionnumber, $visibility) {
|
||||
|
||||
$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));
|
||||
|
||||
$event = \core\event\course_section_updated::create(array(
|
||||
'context' => context_course::instance($courseid),
|
||||
'objectid' => $section->id,
|
||||
'other' => array(
|
||||
'sectionnum' => $sectionnumber
|
||||
)
|
||||
));
|
||||
$event->add_record_snapshot('course_sections', $section);
|
||||
$event->trigger();
|
||||
|
||||
if (!empty($section->sequence)) {
|
||||
$modules = explode(",", $section->sequence);
|
||||
foreach ($modules as $moduleid) {
|
||||
if ($cm = get_coursemodule_from_id(null, $moduleid, $courseid)) {
|
||||
if ($visibility) {
|
||||
// As we unhide the section, we use the previously saved visibility stored in visibleold.
|
||||
set_coursemodule_visible($moduleid, $cm->visibleold);
|
||||
} else {
|
||||
// We hide the section, so we hide the module but we store the original state in visibleold.
|
||||
set_coursemodule_visible($moduleid, 0);
|
||||
$DB->set_field('course_modules', 'visibleold', $cm->visible, array('id' => $moduleid));
|
||||
}
|
||||
\core\event\course_module_updated::create_from_cm($cm)->trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
rebuild_course_cache($courseid, true);
|
||||
course_update_section($courseid, $section, array('visible' => $visibility));
|
||||
|
||||
// Determine which modules are visible for AJAX update
|
||||
$modules = !empty($section->sequence) ? explode(',', $section->sequence) : array();
|
||||
if (!empty($modules)) {
|
||||
list($insql, $params) = $DB->get_in_or_equal($modules);
|
||||
$select = 'id ' . $insql . ' AND visible = ?';
|
||||
@ -1877,6 +1850,70 @@ function course_delete_section($course, $section, $forcedeleteifnotempty = true)
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the course section
|
||||
*
|
||||
* This function does not check permissions or clean values - this has to be done prior to calling it.
|
||||
*
|
||||
* @param int|stdClass $course
|
||||
* @param stdClass $section record from course_sections table - it will be updated with the new values
|
||||
* @param array|stdClass $data
|
||||
*/
|
||||
function course_update_section($course, $section, $data) {
|
||||
global $DB;
|
||||
|
||||
$courseid = (is_object($course)) ? $course->id : (int)$course;
|
||||
|
||||
// Some fields can not be updated using this method.
|
||||
$data = array_diff_key((array)$data, array('id', 'course', 'section', 'sequence'));
|
||||
$changevisibility = (array_key_exists('visible', $data) && (bool)$data['visible'] != (bool)$section->visible);
|
||||
if (array_key_exists('name', $data) && \core_text::strlen($data['name']) > 255) {
|
||||
throw new moodle_exception('maximumchars', 'moodle', '', 255);
|
||||
}
|
||||
|
||||
// Update record in the DB and course format options.
|
||||
$data['id'] = $section->id;
|
||||
$DB->update_record('course_sections', $data);
|
||||
rebuild_course_cache($courseid, true);
|
||||
course_get_format($courseid)->update_section_format_options($data);
|
||||
|
||||
// Update fields of the $section object.
|
||||
foreach ($data as $key => $value) {
|
||||
if (property_exists($section, $key)) {
|
||||
$section->$key = $value;
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger an event for course section update.
|
||||
$event = \core\event\course_section_updated::create(
|
||||
array(
|
||||
'objectid' => $section->id,
|
||||
'courseid' => $courseid,
|
||||
'context' => context_course::instance($courseid),
|
||||
'other' => array('sectionnum' => $section->section)
|
||||
)
|
||||
);
|
||||
$event->trigger();
|
||||
|
||||
// If section visibility was changed, hide the modules in this section too.
|
||||
if ($changevisibility && !empty($section->sequence)) {
|
||||
$modules = explode(',', $section->sequence);
|
||||
foreach ($modules as $moduleid) {
|
||||
if ($cm = get_coursemodule_from_id(null, $moduleid, $courseid)) {
|
||||
if ($data['visible']) {
|
||||
// As we unhide the section, we use the previously saved visibility stored in visibleold.
|
||||
set_coursemodule_visible($moduleid, $cm->visibleold);
|
||||
} else {
|
||||
// We hide the section, so we hide the module but we store the original state in visibleold.
|
||||
set_coursemodule_visible($moduleid, 0);
|
||||
$DB->set_field('course_modules', 'visibleold', $cm->visible, array('id' => $moduleid));
|
||||
}
|
||||
\core\event\course_module_updated::create_from_cm($cm)->trigger();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current user can delete a section (if course format allows it and user has proper permissions).
|
||||
*
|
||||
|
@ -302,6 +302,7 @@ $string['invalidcontext'] = 'Invalid context';
|
||||
$string['invalidcourse'] = 'Invalid course';
|
||||
$string['invalidcourseid'] = 'You are trying to use an invalid course ID';
|
||||
$string['invalidcourselevel'] = 'Incorrect context level';
|
||||
$string['invalidcourseformat'] = 'Invalid course format';
|
||||
$string['invalidcoursemodule'] = 'Invalid course module ID';
|
||||
$string['invalidcoursenameshort'] = 'Invalid short course name';
|
||||
$string['invaliddata'] = 'Data submitted is invalid';
|
||||
|
@ -557,6 +557,7 @@ $string['editorresettodefaults'] = 'Reset to default values';
|
||||
$string['editorsettings'] = 'Editor settings';
|
||||
$string['editorshortcutkeys'] = 'Editor shortcut keys';
|
||||
$string['editsection'] = 'Edit section';
|
||||
$string['editsectionname'] = 'Edit section name';
|
||||
$string['editsummary'] = 'Edit summary';
|
||||
$string['edittitle'] = 'Edit title';
|
||||
$string['edittitleinstructions'] = 'Escape to cancel, Enter when finished';
|
||||
@ -1261,6 +1262,7 @@ Cheers from the \'{$a->sitename}\' administrator,
|
||||
{$a->signoff}';
|
||||
$string['newpicture'] = 'New picture';
|
||||
$string['newpicture_help'] = 'To add a new picture, browse and select an image (in JPG or PNG format) then click "Update profile". The image will be cropped to a square and resized to 100x100 pixels.';
|
||||
$string['newsectionname'] = 'New name for section {$a}';
|
||||
$string['newsitem'] = 'news item';
|
||||
$string['newsitems'] = 'news items';
|
||||
$string['newsitemsnumber'] = 'News items to show';
|
||||
|
Loading…
x
Reference in New Issue
Block a user