diff --git a/blocks/site_main_menu/block_site_main_menu.php b/blocks/site_main_menu/block_site_main_menu.php
index cd26cbc918bb9..866047db83262 100644
--- a/blocks/site_main_menu/block_site_main_menu.php
+++ b/blocks/site_main_menu/block_site_main_menu.php
@@ -51,6 +51,7 @@ function get_content() {
require_once($CFG->dirroot.'/course/lib.php');
$context = context_course::instance($course->id);
$isediting = $this->page->user_is_editing() && has_capability('moodle/course:manageactivities', $context);
+ $courserenderer = $this->page->get_renderer('core', 'course');
/// extra fast view mode
if (!$isediting) {
@@ -69,32 +70,18 @@ function get_content() {
}
if (!empty($cm->url)) {
- $attrs = array();
- $attrs['title'] = $cm->modfullname;
- $attrs['class'] = $cm->extraclasses . ' activity-action';
- if ($cm->onclick) {
- // Get on-click attribute value if specified and decode the onclick - it
- // has already been encoded for display.
- $attrs['onclick'] = htmlspecialchars_decode($cm->onclick);
- }
- if (!$cm->visible) {
- $attrs['class'] .= ' dimmed';
- }
- $icon = '';
- $content = html_writer::link($cm->url, $icon . $cm->get_formatted_name(), $attrs);
+ $content = html_writer::div($courserenderer->course_section_cm_name($cm), 'activity');
} else {
$content = $cm->get_formatted_content(array('overflowdiv' => true, 'noclean' => true));
}
- $this->content->items[] = $indent.html_writer::div($content, 'main-menu-content');
+ $this->content->items[] = $indent . $content;
}
}
return $this->content;
}
// Slow & hacky editing mode.
- /** @var core_course_renderer $courserenderer */
- $courserenderer = $this->page->get_renderer('core', 'course');
$ismoving = ismoving($course->id);
course_create_sections_if_missing($course, 0);
$modinfo = get_fast_modinfo($course);
@@ -104,11 +91,9 @@ function get_content() {
$strmovehere = get_string('movehere');
$strmovefull = strip_tags(get_string('movefull', '', "'$USER->activitycopyname'"));
$strcancel= get_string('cancel');
- $stractivityclipboard = $USER->activitycopyname;
} else {
$strmove = get_string('move');
}
- $editbuttons = '';
if ($ismoving) {
$this->content->icons[] = '';
@@ -116,7 +101,6 @@ function get_content() {
}
if (!empty($modinfo->sections[0])) {
- $options = array('overflowdiv'=>true);
foreach ($modinfo->sections[0] as $modnumber) {
$mod = $modinfo->cms[$modnumber];
if (!$mod->uservisible) {
@@ -153,27 +137,12 @@ function get_content() {
} else {
$indent = '';
}
- $url = $mod->url;
- if (!$url) {
+ if (!$mod->url) {
$content = $mod->get_formatted_content(array('overflowdiv' => true, 'noclean' => true));
} else {
- //Accessibility: incidental image - should be empty Alt text
- $attrs = array();
- $attrs['title'] = $mod->modfullname;
- $attrs['class'] = $mod->extraclasses . ' activity-action';
- if ($mod->onclick) {
- // Get on-click attribute value if specified and decode the onclick - it
- // has already been encoded for display.
- $attrs['onclick'] = htmlspecialchars_decode($mod->onclick);
- }
- if (!$mod->visible) {
- $attrs['class'] .= ' dimmed';
- }
-
- $icon = '';
- $content = html_writer::link($url, $icon . $mod->get_formatted_name(), $attrs);
+ $content = html_writer::div($courserenderer->course_section_cm_name($mod), ' activity');
}
- $this->content->items[] = $indent.html_writer::div($content . $editbuttons, 'main-menu-content');
+ $this->content->items[] = $indent. $content . $editbuttons;
}
}
}
diff --git a/blocks/site_main_menu/styles.css b/blocks/site_main_menu/styles.css
index 0e15ab77f3503..f437bae204bcc 100644
--- a/blocks/site_main_menu/styles.css
+++ b/blocks/site_main_menu/styles.css
@@ -6,5 +6,4 @@
.block_site_main_menu .footer { margin-top: 1em; }
.block_site_main_menu .section_add_menus noscript div { display: inline;}
.block_site_main_menu .mod-indent,
-.block_site_main_menu .main-menu-content { display: table-cell; }
-.block_site_main_menu .main-menu-content > .activity-action { display: block; }
+.block_site_main_menu .activity { display: table-cell; }
diff --git a/blocks/site_main_menu/tests/behat/edit_activities.feature b/blocks/site_main_menu/tests/behat/edit_activities.feature
new file mode 100644
index 0000000000000..b94a0ad51c782
--- /dev/null
+++ b/blocks/site_main_menu/tests/behat/edit_activities.feature
@@ -0,0 +1,21 @@
+@block @block_main_menu
+Feature: Edit activities in main menu block
+ In order to use main menu block
+ As an admin
+ I need to add and edit activities there
+
+ @javascript
+ Scenario: Edit name of acitivity in-place in site main menu block
+ Given I log in as "admin"
+ And I am on site homepage
+ And I navigate to "Turn editing on" node in "Front page settings"
+ When I add a "Forum" to section "0" and I fill the form with:
+ | Forum name | My forum name |
+ And I click on "Edit title" "link" in the "//.[contains(@class,'block_site_main_menu')]//li[contains(.,'My forum name')]" "xpath_element"
+ And I set the field "New name for activity My forum name" to "New forum name"
+ And I press key "13" in the field "New name for activity My forum name"
+ Then I should not see "My forum name"
+ And I should see "New forum name"
+ And I follow "New forum name"
+ And I should not see "My forum name"
+ And I should see "New forum name"
diff --git a/blocks/social_activities/block_social_activities.php b/blocks/social_activities/block_social_activities.php
index 6c6971b013d32..2553413169bbd 100644
--- a/blocks/social_activities/block_social_activities.php
+++ b/blocks/social_activities/block_social_activities.php
@@ -48,6 +48,7 @@ function get_content() {
}
$course = $this->page->course;
+ $courserenderer = $this->page->get_renderer('core', 'course');
require_once($CFG->dirroot.'/course/lib.php');
@@ -58,25 +59,18 @@ function get_content() {
/// extra fast view mode
if (!$isediting) {
if (!empty($modinfo->sections[0])) {
- $options = array('overflowdiv'=>true);
foreach($modinfo->sections[0] as $cmid) {
$cm = $modinfo->cms[$cmid];
if (!$cm->uservisible) {
continue;
}
- $content = $cm->get_formatted_content(array('overflowdiv' => true, 'noclean' => true));
- $instancename = $cm->get_formatted_name();
-
- if (!($url = $cm->url)) {
+ if (!$cm->url) {
+ $content = $cm->get_formatted_content(array('overflowdiv' => true, 'noclean' => true));
$this->content->items[] = $content;
$this->content->icons[] = '';
} else {
- $linkcss = $cm->visible ? '' : ' class="dimmed" ';
- //Accessibility: incidental image - should be empty Alt text
- $icon = ' ';
- $this->content->items[] = 'extra.
- ' href="' . $url . '">' . $icon . $instancename . '';
+ $this->content->items[] = html_writer::div($courserenderer->course_section_cm_name($cm), 'activity');
}
}
}
@@ -85,21 +79,16 @@ function get_content() {
// Slow & hacky editing mode.
- /** @var core_course_renderer $courserenderer */
- $courserenderer = $this->page->get_renderer('core', 'course');
$ismoving = ismoving($course->id);
- $modinfo = get_fast_modinfo($course);
$section = $modinfo->get_section_info(0);
if ($ismoving) {
$strmovehere = get_string('movehere');
$strmovefull = strip_tags(get_string('movefull', '', "'$USER->activitycopyname'"));
$strcancel= get_string('cancel');
- $stractivityclipboard = $USER->activitycopyname;
} else {
$strmove = get_string('move');
}
- $editbuttons = '';
if ($ismoving) {
$this->content->icons[] = ' ';
@@ -107,7 +96,6 @@ function get_content() {
}
if (!empty($modinfo->sections[0])) {
- $options = array('overflowdiv'=>true);
foreach ($modinfo->sections[0] as $modnumber) {
$mod = $modinfo->cms[$modnumber];
if (!$mod->uservisible) {
@@ -139,19 +127,13 @@ function get_content() {
'';
$this->content->icons[] = '';
}
- $content = $mod->get_formatted_content(array('overflowdiv' => true, 'noclean' => true));
- $instancename = $mod->get_formatted_name();
-
- $linkcss = $mod->visible ? '' : ' class="dimmed" ';
-
- if (!($url = $mod->url)) {
+ if (!$mod->url) {
+ $content = $mod->get_formatted_content(array('overflowdiv' => true, 'noclean' => true));
$this->content->items[] = $content . $editbuttons;
$this->content->icons[] = '';
} else {
- //Accessibility: incidental image - should be empty Alt text
- $icon = ' ';
- $this->content->items[] = 'extra .
- ' href="' . $url . '">' . $icon . $instancename . '' . $editbuttons;
+ $this->content->items[] = html_writer::div($courserenderer->course_section_cm_name($mod), 'activity') .
+ $editbuttons;
}
}
}
diff --git a/blocks/social_activities/tests/behat/edit_activities.feature b/blocks/social_activities/tests/behat/edit_activities.feature
new file mode 100644
index 0000000000000..1db7a7ff9897c
--- /dev/null
+++ b/blocks/social_activities/tests/behat/edit_activities.feature
@@ -0,0 +1,31 @@
+@block @block_social_activities
+Feature: Edit activities in social activities block
+ In order to use social activities block
+ As a teacher
+ I need to add and edit activities there
+
+ @javascript
+ Scenario: Edit name of acitivity in-place in social activities block
+ Given the following "courses" exist:
+ | fullname | shortname | format |
+ | Course 1 | C1 | social |
+ And the following "users" exist:
+ | username | firstname | lastname |
+ | user1 | User | One |
+ And the following "course enrolments" exist:
+ | user | course | role |
+ | user1 | C1 | editingteacher |
+ Given I log in as "user1"
+ And I follow "Course 1"
+ And I turn editing mode on
+ And I set the field "Add an activity to section 'section 0'" to "Forum"
+ And I set the field "Forum name" to "My forum name"
+ And I press "Save and return to course"
+ And I click on "Edit title" "link" in the "//.[contains(@class,'block_social_activities')]//li[contains(.,'My forum name')]" "xpath_element"
+ And I set the field "New name for activity My forum name" to "New forum name"
+ And I press key "13" in the field "New name for activity My forum name"
+ Then I should not see "My forum name" in the "Social activities" "block"
+ And I should see "New forum name"
+ And I follow "New forum name"
+ And I should not see "My forum name"
+ And I should see "New forum name"
diff --git a/course/classes/output/course_module_name.php b/course/classes/output/course_module_name.php
new file mode 100644
index 0000000000000..e286e555b2d7e
--- /dev/null
+++ b/course/classes/output/course_module_name.php
@@ -0,0 +1,100 @@
+.
+
+/**
+ * Contains class core_tag\output\course_module_name
+ *
+ * @package core_course
+ * @copyright 2016 Marina Glancy
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+
+namespace core_course\output;
+
+use context_module;
+use lang_string;
+use cm_info;
+
+/**
+ * Class to prepare a course module name for display and in-place editing
+ *
+ * @package core_course
+ * @copyright 2016 Marina Glancy
+ * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
+ */
+class course_module_name extends \core\output\inplace_editable {
+
+ /** @var cm_info */
+ protected $cm;
+
+ /** @var array */
+ protected $displayoptions;
+
+ /**
+ * Constructor.
+ *
+ * @param cm_info $cm
+ * @param bool $editable
+ * @param array $displayoptions
+ */
+ public function __construct(cm_info $cm, $editable, $displayoptions = array()) {
+ $this->cm = $cm;
+ $this->displayoptions = $displayoptions;
+ $value = $cm->name;
+ $edithint = new lang_string('edittitle');
+ $editlabel = new lang_string('newactivityname', '', $cm->get_formatted_name());
+ $editable = $editable && has_capability('moodle/course:manageactivities',
+ context_module::instance($cm->id));
+ parent::__construct(
+ 'core_course', 'activityname', $cm->id, $editable, $value, $value, $edithint, $editlabel);
+ }
+
+ /**
+ * Export this data so it can be used as the context for a mustache template (core/inplace_editable).
+ *
+ * @param renderer_base $output typically, the renderer that's calling this function
+ * @return array data context for a mustache template
+ */
+ public function export_for_template(\renderer_base $output) {
+ global $PAGE;
+ $courserenderer = $PAGE->get_renderer('core', 'course');
+ $this->displayvalue = $courserenderer->course_section_cm_name_title($this->cm, $this->displayoptions);
+ if (strval($this->displayvalue) === '') {
+ $this->editable = false;
+ }
+ return parent::export_for_template($output);
+ }
+
+ /**
+ * Updates course module name
+ *
+ * @param int $itemid course module id
+ * @param string $newvalue new name
+ * @return static
+ */
+ public static function update($itemid, $newvalue) {
+ list($course, $cm) = get_course_and_cm_from_cmid($itemid);
+ $context = context_module::instance($cm->id);
+ // Check access.
+ require_login($course, false, $cm, true, true);
+ require_capability('moodle/course:manageactivities', $context);
+ // Update value.
+ set_coursemodule_name($cm->id, $newvalue);
+ // Return instance.
+ $cm = get_fast_modinfo($course)->get_cm($cm->id);
+ return new static($cm, true);
+ }
+}
diff --git a/course/lib.php b/course/lib.php
index 6afaae0a7e874..59b69e7d84563 100644
--- a/course/lib.php
+++ b/course/lib.php
@@ -1605,6 +1605,50 @@ function set_coursemodule_visible($id, $visible) {
return true;
}
+/**
+ * Changes the course module name
+ *
+ * @param int $id course module id
+ * @param string $name new value for a name
+ * @return bool whether a change was made
+ */
+function set_coursemodule_name($id, $name) {
+ global $CFG, $DB;
+ require_once($CFG->libdir . '/gradelib.php');
+
+ $cm = get_coursemodule_from_id('', $id, 0, false, MUST_EXIST);
+
+ $module = new \stdClass();
+ $module->id = $cm->instance;
+
+ // Escape strings as they would be by mform.
+ if (!empty($CFG->formatstringstriptags)) {
+ $module->name = clean_param($name, PARAM_TEXT);
+ } else {
+ $module->name = clean_param($name, PARAM_CLEANHTML);
+ }
+ if ($module->name === $cm->name || strval($module->name) === '') {
+ return false;
+ }
+ if (\core_text::strlen($module->name) > 255) {
+ throw new \moodle_exception('maximumchars', 'moodle', '', 255);
+ }
+
+ $module->timemodified = time();
+ $DB->update_record($cm->modname, $module);
+ $cm->name = $module->name;
+ \core\event\course_module_updated::create_from_cm($cm)->trigger();
+ rebuild_course_cache($cm->course, true);
+
+ // Attempt to update the grade item if relevant.
+ $grademodule = $DB->get_record($cm->modname, array('id' => $cm->instance));
+ $grademodule->cmidnumber = $cm->idnumber;
+ $grademodule->modname = $cm->modname;
+ grade_update_mod_grades($grademodule);
+
+ return true;
+}
+
/**
* This function will handle the whole deletion process of a module. This includes calling
* the modules delete_instance function, deleting files, events, grades, conditional data,
@@ -2241,53 +2285,6 @@ function course_get_cm_edit_actions(cm_info $mod, $indent = -1, $sr = null) {
return $actions;
}
-/**
- * Returns the rename action.
- *
- * @param cm_info $mod The module to produce editing buttons for
- * @param int $sr The section to link back to (used for creating the links)
- * @return The markup for the rename action, or an empty string if not available.
- */
-function course_get_cm_rename_action(cm_info $mod, $sr = null) {
- global $COURSE, $OUTPUT;
-
- static $str;
- static $baseurl;
-
- $modcontext = context_module::instance($mod->id);
- $hasmanageactivities = has_capability('moodle/course:manageactivities', $modcontext);
-
- if (!isset($str)) {
- $str = get_strings(array('edittitle'));
- }
-
- if (!isset($baseurl)) {
- $baseurl = new moodle_url('/course/mod.php', array('sesskey' => sesskey()));
- }
-
- if ($sr !== null) {
- $baseurl->param('sr', $sr);
- }
-
- // AJAX edit title.
- if ($mod->has_view() && $hasmanageactivities && course_ajax_enabled($COURSE) &&
- (($mod->course == $COURSE->id) || ($mod->course == SITEID))) {
- // we will not display link if we are on some other-course page (where we should not see this module anyway)
- return html_writer::span(
- html_writer::link(
- new moodle_url($baseurl, array('update' => $mod->id)),
- $OUTPUT->pix_icon('t/editstring', '', 'moodle', array('class' => 'iconsmall visibleifjs', 'title' => '')),
- array(
- 'class' => 'editing_title',
- 'data-action' => 'edittitle',
- 'title' => $str->edittitle,
- )
- )
- );
- }
- return '';
-}
-
/**
* Returns the move action.
*
@@ -3897,3 +3894,17 @@ function course_get_tagged_courses($tag, $exclusivemode = false, $fromctx = 0, $
return new core_tag\output\tagindex($tag, 'core', 'course', $content,
$exclusivemode, $fromctx, $ctx, $rec, $page, $totalpages);
}
+
+/**
+ * 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 core_course_inplace_editable($itemtype, $itemid, $newvalue) {
+ if ($itemtype === 'activityname') {
+ return \core_course\output\course_module_name::update($itemid, $newvalue);
+ }
+}
diff --git a/course/renderer.php b/course/renderer.php
index b71d4882d410e..617f4e81315ce 100644
--- a/course/renderer.php
+++ b/course/renderer.php
@@ -733,10 +733,34 @@ protected function is_cm_conditionally_hidden(cm_info $mod) {
* @return string
*/
public function course_section_cm_name(cm_info $mod, $displayoptions = array()) {
- global $CFG;
+ if ((!$mod->uservisible && empty($mod->availableinfo)) || !$mod->url) {
+ // Nothing to be displayed to the user.
+ return '';
+ }
+
+ // Render element that allows to edit activity name inline. It calls {@link course_section_cm_name_title()}
+ // to get the display title of the activity.
+ $tmpl = new \core_course\output\course_module_name($mod, $this->page->user_is_editing(), $displayoptions);
+ return $this->output->render_from_template('core/inplace_editable', $tmpl->export_for_template($this->output));
+ }
+
+ /**
+ * Renders html to display a name with the link to the course module on a course page
+ *
+ * If module is unavailable for user but still needs to be displayed
+ * in the list, just the name is returned without a link
+ *
+ * Note, that for course modules that never have separate pages (i.e. labels)
+ * this function return an empty string
+ *
+ * @param cm_info $mod
+ * @param array $displayoptions
+ * @return string
+ */
+ public function course_section_cm_name_title(cm_info $mod, $displayoptions = array()) {
$output = '';
if (!$mod->uservisible && empty($mod->availableinfo)) {
- // nothing to be displayed to the user
+ // Nothing to be displayed to the user.
return $output;
}
$url = $mod->url;
@@ -985,10 +1009,6 @@ public function course_section_cm($course, &$completioninfo, cm_info $mod, $sect
$output .= $cmname;
- if ($this->page->user_is_editing()) {
- $output .= ' ' . course_get_cm_rename_action($mod, $sectionreturn);
- }
-
// Module can put text after the link (e.g. forum unread)
$output .= $mod->afterlink;
diff --git a/course/rest.php b/course/rest.php
index 675f3671e961a..42b45ce1303d4 100644
--- a/course/rest.php
+++ b/course/rest.php
@@ -150,49 +150,6 @@
$isvisible = moveto_module($cm, $section, $beforemod);
echo json_encode(array('visible' => (bool) $isvisible));
break;
- case 'gettitle':
- require_capability('moodle/course:manageactivities', $modcontext);
- $cm = get_coursemodule_from_id('', $id, 0, false, MUST_EXIST);
- $module = new stdClass();
- $module->id = $cm->instance;
-
- // Don't pass edit strings through multilang filters - we need the entire string
- echo json_encode(array('instancename' => $cm->name));
- break;
- case 'updatetitle':
- require_capability('moodle/course:manageactivities', $modcontext);
- require_once($CFG->libdir . '/gradelib.php');
- $cm = get_coursemodule_from_id('', $id, 0, false, MUST_EXIST);
- $module = new stdClass();
- $module->id = $cm->instance;
-
- // Escape strings as they would be by mform
- if (!empty($CFG->formatstringstriptags)) {
- $module->name = clean_param($title, PARAM_TEXT);
- } else {
- $module->name = clean_param($title, PARAM_CLEANHTML);
- }
-
- if (strval($module->name) !== '') {
- $DB->update_record($cm->modname, $module);
- $cm->name = $module->name;
- \core\event\course_module_updated::create_from_cm($cm, $modcontext)->trigger();
- rebuild_course_cache($cm->course);
- } else {
- $module->name = $cm->name;
- }
-
- // Attempt to update the grade item if relevant
- $grademodule = $DB->get_record($cm->modname, array('id' => $cm->instance));
- $grademodule->cmidnumber = $cm->idnumber;
- $grademodule->modname = $cm->modname;
- grade_update_mod_grades($grademodule);
-
- // We need to return strings after they've been through filters for multilang
- $stringoptions = new stdClass;
- $stringoptions->context = $coursecontext;
- echo json_encode(array('instancename' => html_entity_decode(format_string($module->name, true, $stringoptions))));
- break;
}
break;
diff --git a/course/tests/behat/activities_edit_name.feature b/course/tests/behat/activities_edit_name.feature
new file mode 100644
index 0000000000000..2d53b7cc8fc3b
--- /dev/null
+++ b/course/tests/behat/activities_edit_name.feature
@@ -0,0 +1,44 @@
+@core @core_course
+Feature: Edit activity name in-place
+ In order to quickly edit activity name
+ As a teacher
+ I need to use inplace editing
+
+ @javascript
+ Scenario: Edit activity name in-place
+ Given the following "users" exist:
+ | username | firstname | lastname | email |
+ | teacher1 | Teacher | 1 | teacher1@example.com |
+ And the following "courses" exist:
+ | fullname | shortname | format |
+ | Course 1 | C1 | topics |
+ And the following "course enrolments" exist:
+ | user | course | role |
+ | teacher1 | C1 | editingteacher |
+ When I log in as "teacher1"
+ And I follow "Course 1"
+ And I turn editing mode on
+ And I add a "Forum" to section "1" and I fill the form with:
+ | Forum name | Test forum name |
+ | Description | Test forum description |
+ # Rename activity
+ And I click on "Edit title" "link" in the "//div[contains(@class,'activityinstance') and contains(.,'Test forum name')]" "xpath_element"
+ And I set the field "New name for activity Test forum name" to "Good news"
+ And I press key "13" in the field "New name for activity Test forum name"
+ Then I should not see "Test forum name" in the ".course-content" "css_element"
+ And "New name for activity Test forum name" "field" should not exist
+ And I should see "Good news"
+ And I follow "Course 1"
+ And I should see "Good news"
+ And I should not see "Test forum name"
+ # Cancel renaming
+ And I click on "Edit title" "link" in the "//div[contains(@class,'activityinstance') and contains(.,'Good news')]" "xpath_element"
+ And I set the field "New name for activity Good news" to "Terrible news"
+ And I press key "27" in the field "New name for activity Good news"
+ And "New name for activity Good news" "field" should not exist
+ And I should see "Good news"
+ And I should not see "Terrible news"
+ And I follow "Course 1"
+ And I should see "Good news"
+ And I should not see "Terrible news"
+ And I log out
diff --git a/course/tests/behat/behat_course.php b/course/tests/behat/behat_course.php
index 344a208c3dfeb..05a096f6ff374 100644
--- a/course/tests/behat/behat_course.php
+++ b/course/tests/behat/behat_course.php
@@ -467,7 +467,7 @@ public function section_activities_should_be_hidden($sectionnumber) {
foreach ($activities as $activity) {
// Dimmed.
$this->find('xpath', "//div[contains(concat(' ', normalize-space(@class), ' '), ' activityinstance ')]" .
- "/a[contains(concat(' ', normalize-space(@class), ' '), ' dimmed ')]", $dimmedexception, $activity);
+ "//a[contains(concat(' ', normalize-space(@class), ' '), ' dimmed ')]", $dimmedexception, $activity);
}
}
} else {
diff --git a/course/tests/courselib_test.php b/course/tests/courselib_test.php
index 0e4e9dea6102f..aa50329657f34 100644
--- a/course/tests/courselib_test.php
+++ b/course/tests/courselib_test.php
@@ -2779,4 +2779,34 @@ public function test_empty_availability_settings() {
$this->assertNull($DB->get_field('course_modules', 'availability',
array('id' => $label->cmid)));
}
+
+ /**
+ * Test update_inplace_editable()
+ */
+ public function test_update_module_name_inplace() {
+ global $CFG, $DB, $PAGE;
+ require_once($CFG->dirroot . '/lib/external/externallib.php');
+
+ $this->setUser($this->getDataGenerator()->create_user());
+
+ $this->resetAfterTest(true);
+ $course = $this->getDataGenerator()->create_course();
+ $forum = self::getDataGenerator()->create_module('forum', array('course' => $course->id, 'name' => 'forum name'));
+
+ // Call service for core_course component without necessary permissions.
+ try {
+ core_external::update_inplace_editable('core_course', 'activityname', $forum->cmid, 'New forum name');
+ $this->fail('Exception expected');
+ } catch (moodle_exception $e) {
+ $this->assertEquals('Course or activity not accessible. (Not enrolled)',
+ $e->getMessage());
+ }
+
+ // Change to admin user and make sure that cm name can be updated using web service update_inplace_editable().
+ $this->setAdminUser();
+ $res = core_external::update_inplace_editable('core_course', 'activityname', $forum->cmid, 'New forum name');
+ $res = external_api::clean_returnvalue(core_external::update_inplace_editable_returns(), $res);
+ $this->assertEquals('New forum name', $res['value']);
+ $this->assertEquals('New forum name', $DB->get_field('forum', 'name', array('id' => $forum->id)));
+ }
}
diff --git a/course/yui/build/moodle-course-toolboxes/moodle-course-toolboxes-debug.js b/course/yui/build/moodle-course-toolboxes/moodle-course-toolboxes-debug.js
index 03d72a6199038..75ef3b8772fc4 100644
--- a/course/yui/build/moodle-course-toolboxes/moodle-course-toolboxes-debug.js
+++ b/course/yui/build/moodle-course-toolboxes/moodle-course-toolboxes-debug.js
@@ -19,31 +19,28 @@ var CSS = {
DIMCLASS : 'dimmed',
DIMMEDTEXT : 'dimmed_text',
EDITINSTRUCTIONS : 'editinstructions',
- EDITINGTITLE: 'editor_displayed',
HIDE : 'hide',
MODINDENTCOUNT : 'mod-indent-',
MODINDENTHUGE : 'mod-indent-huge',
MODULEIDPREFIX : 'module-',
SECTIONHIDDENCLASS : 'hidden',
SECTIONIDPREFIX : 'section-',
- SHOW : 'editing_show',
- TITLEEDITOR : 'titleeditor'
+ SHOW : 'editing_show'
},
// The CSS selectors we use.
SELECTOR = {
ACTIONAREA: '.actions',
ACTIONLINKTEXT : '.actionlinktext',
- ACTIVITYACTION : 'a.cm-edit-action[data-action], a.editing_title',
- ACTIVITYFORM : '.' + CSS.ACTIVITYINSTANCE + ' form',
+ ACTIVITYACTION : 'a.cm-edit-action[data-action]',
ACTIVITYICON : 'img.activityicon',
ACTIVITYINSTANCE : '.' + CSS.ACTIVITYINSTANCE,
- ACTIVITYLINK: '.' + CSS.ACTIVITYINSTANCE + ' > a',
+ ACTIVITYLINK: '.' + CSS.ACTIVITYINSTANCE + ' > a, .'+ CSS.ACTIVITYINSTANCE +
+ ' > span[data-inplaceeditable] > a:not([data-inplaceeditablelink])',
ACTIVITYLI : 'li.activity',
- ACTIVITYTITLE : 'input[name=title]',
COMMANDSPAN : '.commands',
CONTENTAFTERLINK : 'div.contentafterlink',
CONTENTWITHOUTLINK : 'div.contentwithoutlink',
- EDITTITLE: 'a.editing_title',
+ GROUPINGLABEL: '.' + CSS.ACTIVITYINSTANCE + ' .groupinglabel',
HIDE : 'a.editing_hide',
HIGHLIGHT : 'a.editing_highlight',
INSTANCENAME : 'span.instancename',
@@ -256,17 +253,6 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
*/
GROUPS_VISIBLE: 2,
- /**
- * An Array of events added when editing a title.
- * These should all be detached when editing is complete.
- *
- * @property edittitleevents
- * @protected
- * @type Array
- * @protected
- */
- edittitleevents: [],
-
/**
* Initialize the resource toolbox
*
@@ -317,10 +303,6 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
// Switch based upon the action and do the desired thing.
switch (action) {
- case 'edittitle':
- // The user wishes to edit the title of the event.
- this.edit_title(ev, node, activity, action);
- break;
case 'moveleft':
case 'moveright':
// The user changing the indent of the activity.
@@ -633,11 +615,13 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
dimarea.addClass(toggleclass);
// We need to toggle dimming on the description too.
activity.all(SELECTOR.CONTENTAFTERLINK).addClass(CSS.DIMMEDTEXT);
+ activity.all(SELECTOR.GROUPINGLABEL).addClass(CSS.DIMMEDTEXT);
} else {
// Change the UI.
dimarea.removeClass(toggleclass);
// We need to toggle dimming on the description too.
activity.all(SELECTOR.CONTENTAFTERLINK).removeClass(CSS.DIMMEDTEXT);
+ activity.all(SELECTOR.GROUPINGLABEL).removeClass(CSS.DIMMEDTEXT);
}
}
// Toggle availablity info for conditional activities.
@@ -714,172 +698,6 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
return this;
},
- /**
- * Edit the title for the resource
- *
- * @method edit_title
- * @protected
- * @param {EventFacade} ev The event that was fired.
- * @param {Node} button The button that triggered this action.
- * @param {Node} activity The activity node that this action will be performed on.
- * @param {String} action The action that has been requested.
- * @chainable
- */
- edit_title: function(ev, button, activity) {
- // Get the element we're working on
- var activityid = Y.Moodle.core_course.util.cm.getId(activity),
- instancename = activity.one(SELECTOR.INSTANCENAME),
- instance = activity.one(SELECTOR.ACTIVITYINSTANCE),
- currenttitle = instancename.get('firstChild'),
- oldtitle = currenttitle.get('data'),
- titletext = oldtitle,
- thisevent,
- anchor = instancename.ancestor('a'),// Grab the anchor so that we can swap it with the edit form.
- data = {
- 'class': 'resource',
- 'field': 'gettitle',
- 'id': activityid
- };
-
- // Prevent the default actions.
- ev.preventDefault();
-
- this.send_request(data, null, function(response) {
- if (M.core.actionmenu && M.core.actionmenu.instance) {
- M.core.actionmenu.instance.hideMenu(ev);
- }
-
- // Try to retrieve the existing string from the server
- if (response.instancename) {
- titletext = response.instancename;
- }
-
- // Create the editor and submit button
- var editform = Y.Node.create('
');
- var editinstructions = Y.Node.create('')
- .set('innerHTML', M.util.get_string('edittitleinstructions', 'moodle'));
- var editor = Y.Node.create('').setAttrs({
- 'value': titletext,
- 'autocomplete': 'off',
- 'aria-describedby': 'id_editinstructions',
- 'maxLength': '255'
- });
-
- // Clear the existing content and put the editor in
- editform.appendChild(activity.one(SELECTOR.ACTIVITYICON).cloneNode());
- editform.appendChild(editor);
- editform.setData('anchor', anchor);
- instance.insert(editinstructions, 'before');
- anchor.replace(editform);
-
- // Force the editing instruction to match the mod-indent position.
- var padside = 'left';
- if (window.right_to_left()) {
- padside = 'right';
- }
-
- // We hide various components whilst editing:
- activity.addClass(CSS.EDITINGTITLE);
-
- // Focus and select the editor text
- editor.focus().select();
-
- // Cancel the edit if we lose focus or the escape key is pressed.
- thisevent = editor.on('blur', this.edit_title_cancel, this, activity, false);
- this.edittitleevents.push(thisevent);
- thisevent = editor.on('key', this.edit_title_cancel, 'esc', this, activity, true);
- this.edittitleevents.push(thisevent);
-
- // Handle form submission.
- thisevent = editform.on('submit', this.edit_title_submit, this, activity, oldtitle);
- this.edittitleevents.push(thisevent);
- });
- return this;
- },
-
- /**
- * Handles the submit event when editing the activity or resources title.
- *
- * @method edit_title_submit
- * @protected
- * @param {EventFacade} ev The event that triggered this.
- * @param {Node} activity The activity whose title we are altering.
- * @param {String} originaltitle The original title the activity or resource had.
- */
- edit_title_submit: function(ev, activity, originaltitle) {
- // We don't actually want to submit anything
- ev.preventDefault();
-
- var newtitle = Y.Lang.trim(activity.one(SELECTOR.ACTIVITYFORM + ' ' + SELECTOR.ACTIVITYTITLE).get('value'));
- this.edit_title_clear(activity);
- var spinner = this.add_spinner(activity);
- if (newtitle !== null && newtitle !== "" && newtitle !== originaltitle) {
- var data = {
- 'class': 'resource',
- 'field': 'updatetitle',
- 'title': newtitle,
- 'id': Y.Moodle.core_course.util.cm.getId(activity)
- };
- this.send_request(data, spinner, function(response) {
- if (response.instancename) {
- activity.one(SELECTOR.INSTANCENAME).setContent(response.instancename);
- }
- });
- }
- },
-
- /**
- * Handles the cancel event when editing the activity or resources title.
- *
- * @method edit_title_cancel
- * @protected
- * @param {EventFacade} ev The event that triggered this.
- * @param {Node} activity The activity whose title we are altering.
- * @param {Boolean} preventdefault If true we should prevent the default action from occuring.
- */
- edit_title_cancel: function(ev, activity, preventdefault) {
- if (preventdefault) {
- ev.preventDefault();
- }
- this.edit_title_clear(activity);
- },
-
- /**
- * Handles clearing the editing UI and returning things to the original state they were in.
- *
- * @method edit_title_clear
- * @protected
- * @param {Node} activity The activity whose title we were altering.
- */
- edit_title_clear: function(activity) {
- // Detach all listen events to prevent duplicate triggers
- new Y.EventHandle(this.edittitleevents).detach();
-
- var editform = activity.one(SELECTOR.ACTIVITYFORM),
- instructions = activity.one('#id_editinstructions');
- if (editform) {
- editform.replace(editform.getData('anchor'));
- }
- if (instructions) {
- instructions.remove();
- }
-
- // Remove the editing class again to revert the display.
- activity.removeClass(CSS.EDITINGTITLE);
-
- // Refocus the link which was clicked originally so the user can continue using keyboard nav.
- Y.later(100, this, function() {
- activity.one(SELECTOR.EDITTITLE).focus();
- });
-
- // TODO MDL-50768 This hack is to keep Behat happy until they release a version of
- // MinkSelenium2Driver that fixes
- // https://github.com/Behat/MinkSelenium2Driver/issues/80.
- if (!Y.one('input[name=title]')) {
- Y.one('body').append('');
- }
- },
-
/**
* Set the visibility of the specified resource to match the visible parameter.
*
diff --git a/course/yui/build/moodle-course-toolboxes/moodle-course-toolboxes-min.js b/course/yui/build/moodle-course-toolboxes/moodle-course-toolboxes-min.js
index ec2b8fab4c329..290b316e7e407 100644
--- a/course/yui/build/moodle-course-toolboxes/moodle-course-toolboxes-min.js
+++ b/course/yui/build/moodle-course-toolboxes/moodle-course-toolboxes-min.js
@@ -1,3 +1,2 @@
-YUI.add("moodle-course-toolboxes",function(e,t){var n={ACTIVITYINSTANCE:"activityinstance",AVAILABILITYINFODIV:"div.availabilityinfo",CONTENTWITHOUTLINK:"contentwithoutlink",CONDITIONALHIDDEN:"conditionalhidden",DIMCLASS:"dimmed",DIMMEDTEXT:"dimmed_text",EDITINSTRUCTIONS:"editinstructions",EDITINGTITLE:"editor_displayed",HIDE:"hide",MODINDENTCOUNT:"mod-indent-",MODINDENTHUGE:"mod-indent-huge",MODULEIDPREFIX:"module-",SECTIONHIDDENCLASS:"hidden",SECTIONIDPREFIX:"section-",SHOW:"editing_show",TITLEEDITOR:"titleeditor"},r={ACTIONAREA:".actions",ACTIONLINKTEXT:".actionlinktext",ACTIVITYACTION:"a.cm-edit-action[data-action], a.editing_title",ACTIVITYFORM:"."+n.ACTIVITYINSTANCE+" form",ACTIVITYICON:"img.activityicon",ACTIVITYINSTANCE:"."+n.ACTIVITYINSTANCE,ACTIVITYLINK:"."+n.ACTIVITYINSTANCE+" > a",ACTIVITYLI:"li.activity",ACTIVITYTITLE:"input[name=title]",COMMANDSPAN:".commands",CONTENTAFTERLINK:"div.contentafterlink",CONTENTWITHOUTLINK:"div.contentwithoutlink",EDITTITLE:"a.editing_title",HIDE:"a.editing_hide",HIGHLIGHT:"a.editing_highlight",INSTANCENAME:"span.instancename",MODINDENTDIV:".mod-indent",MODINDENTOUTER:".mod-indent-outer",PAGECONTENT:"body",SECTIONLI:"li.section",SHOW:"a."+n.SHOW,SHOWHIDE:"a.editing_showhide"},i={MIN:0,MAX:16},s=e.one(document.body);M.course=M.course||{};var o=function(){o.superclass.constructor.apply(this,arguments)};e.extend(o,e.Base,{send_request:function(t,n,r,i){t||(t={});var s=this.get("config").pageparams,o;for(o in s)t[o]=s[o];t.sesskey=M.cfg.sesskey,t.courseId=this.get("courseid");var u=M.cfg.wwwroot+this.get("ajaxurl"),a=[],f={method:"POST",data:t,on:{success:function(t,i){try{a=e.JSON.parse(i.responseText),a.error&&new M.core.ajaxException(a)}catch(s){}r&&e.bind(r,this,a)(),n&&window.setTimeout(function(){n.hide()},400)},failure:function(e,t){n&&n.hide(),new M.core.ajaxException(t)}},context:this};if(i)for(o in i)f[o]=i[o];return n&&n.show(),e.io(u,f),this}},{NAME:"course-toolbox",ATTRS:{courseid:{value:0},format:{value:"topics"},ajaxurl:{value:null},config:{value:{}}}});var u=function(){u.superclass.constructor.apply(this,arguments)};e.extend(u,o,{GROUPS_NONE:0,GROUPS_SEPARATE:1,GROUPS_VISIBLE:2,edittitleevents:[],initializer:function(){M.course.coursebase.register_module(this),s.delegate("key",this.handle_data_action,"down:enter",r.ACTIVITYACTION,this),e.delegate("click",this.handle_data_action,s,r.ACTIVITYACTION,this)},handle_data_action:function(e){var t=e.target;t.test("a")||(t=t.ancestor(r.ACTIVITYACTION));var n=t.getData("action"),i=t.ancestor(r.ACTIVITYLI);if(!t.test("a")||!n||!i)return;switch(n){case"edittitle":this.edit_title(e,t,i,n);break;case"moveleft":case"moveright":this.change_indent(e,t,i,n);break;case"delete":this.delete_with_confirmation(e,t,i,n);break;case"duplicate":this.duplicate(e,t,i,n);break;case"hide":case"show":this.change_visibility(e,t,i,n);break;case"groupsseparate":case"groupsvisible":case"groupsnone":this.change_groupmode(e,t,i,n);break;case"move":case"update":case"duplicate":case"assignroles":break;default:}},add_spinner:function(t){var n=t.one(r.ACTIONAREA);return n?M.util.add_spinner(e,n):null},change_indent:function(t,s,o,u){t.preventDefault();var a=u==="moveleft"?-1:1,f=o.one(r.MODINDENTDIV),l=f.getAttribute("class").match(/mod-indent-(\d{1,})/),c=0,h;l&&(c=parseInt(l[1],10)),h=c+parseInt(a,10);if(hi.MAX)return;l&&f.removeClass(l[0]),f.addClass(n.MODINDENTCOUNT+h);var p={"class":"resource",field:"indent",value:h,id:e.Moodle.core_course.util.cm.getId(o)},d=this.add_spinner(o);this.send_request(p,d);var v;h===i.MIN?(s.addClass("hidden"),v=o.one(".editing_moveright")):h>i.MIN&&c===i.MIN&&s.ancestor(".menu").one("[data-action=moveleft]").removeClass("hidden"),h===i.MAX?(s.addClass("hidden"),v=o.one(".editing_moveleft")):h15&&!m?f.addClass(n.MODINDENTHUGE):h<=15&&m&&f.removeClass(n.MODINDENTHUGE),t.type&&t.type==="key"&&v&&v.focus()},delete_with_confirmation:function(t,n,r){t.preventDefault();var i=r,s="",o={type:M.util.get_string("pluginname",i.getAttribute("class").match(/modtype_([^\s]*)/)[1])};e.Moodle.core_course.util.cm.getName(i)!==null?(o.name=e.Moodle.core_course.util.cm.getName(i),s=M.util.get_string("deletechecktypename","moodle",o)):s=M.util.get_string("deletechecktype","moodle",o);var u=new M.core.confirm({question:s,modal:!0,visible:!1});return u.show(),u.on("complete-yes",function(){i.remove();var n={"class":"resource",action:"DELETE",id:e.Moodle.core_course.util.cm.getId(i)};this.send_request(n),M.core.actionmenu&&M.core.actionmenu.instance&&M.core.actionmenu.instance.hideMenu(t)},this),this},duplicate:function(t,n,r){t.preventDefault();var i=r,s=r.ancestor(M.course.format.get_section_selector(e)),o=M.util.add_lightbox(e,s).show(),u={"class":"resource",field:"duplicate",id:e.Moodle.core_course.util.cm.getId(i),sr:n.getData("sr")};return this.send_request(u,o,function(t){var n=e.Node.create(t.fullcontent);r.insert(n,"after"),e.use("moodle-course-coursebase",function(){M.course.coursebase.invoke_function("setup_for_resource",n)}),M.core.actionmenu&&M.core.actionmenu.newDOMNode&&M.core.actionmenu.newDOMNode(n)}),this},change_visibility:function(t,n,r,i){t.preventDefault();var s=r,o=this.handle_resource_dim(n,r,i),u={"class":"resource",field:"visible",value:o,id:e.Moodle.core_course.util.cm.getId(s)},a=this.add_spinner(s);return this.send_request(u,a),this},handle_resource_dim:function(t,i,s){var o=n.DIMCLASS,u=i.one([r.ACTIVITYLINK,r.CONTENTWITHOUTLINK].join(", ")),a=i.one(n.AVAILABILITYINFODIV),f=s==="hide"?"show":"hide",l=t.one("span"),c=M.util.get_string(f,"moodle"),h=t.one("img");return h.setAttrs({src:M.util.image_url("t/"+f)}),e.Lang.trim(t.getAttribute("title"))&&t.setAttribute("title",c),e.Lang.trim(h.getAttribute("alt"))&&h.setAttribute("alt",c),t.replaceClass("editing_"+s,"editing_"+f),t.setData("action",f),l&&l.set("text",c),i.one(r.CONTENTWITHOUTLINK)&&(u=i.one(
-r.CONTENTWITHOUTLINK),o=n.DIMMEDTEXT),u.hasClass(n.CONDITIONALHIDDEN)||(s==="hide"?(u.addClass(o),i.all(r.CONTENTAFTERLINK).addClass(n.DIMMEDTEXT)):(u.removeClass(o),i.all(r.CONTENTAFTERLINK).removeClass(n.DIMMEDTEXT))),a&&a.toggleClass(n.HIDE),s==="hide"?0:1},change_groupmode:function(t,n,r){t.preventDefault();var i=parseInt(n.getData("nextgroupmode"),10),s="",o="",u,a,f,l=i+1,c=n.one("img");l>2&&(l=0),i===this.GROUPS_NONE?(s="groupsnone",o=M.util.image_url("i/groupn","moodle")):i===this.GROUPS_SEPARATE?(s="groupsseparate",o=M.util.image_url("i/groups","moodle")):i===this.GROUPS_VISIBLE&&(s="groupsvisible",o=M.util.image_url("i/groupv","moodle")),u=M.util.get_string("clicktochangeinbrackets","moodle",M.util.get_string(s,"moodle"));var h=n.getData("action");return n.replaceClass("editing_"+h,"editing_"+s),c.setAttrs({src:o}),e.Lang.trim(n.getAttribute("title"))&&n.setAttribute("title",u).setData("action",s).setData("nextgroupmode",l),e.Lang.trim(c.getAttribute("alt"))&&c.setAttribute("alt",u),a={"class":"resource",field:"groupmode",value:i,id:e.Moodle.core_course.util.cm.getId(r)},f=this.add_spinner(r),this.send_request(a,f),this},edit_title:function(t,i,s){var o=e.Moodle.core_course.util.cm.getId(s),u=s.one(r.INSTANCENAME),a=s.one(r.ACTIVITYINSTANCE),f=u.get("firstChild"),l=f.get("data"),c=l,h,p=u.ancestor("a"),d={"class":"resource",field:"gettitle",id:o};return t.preventDefault(),this.send_request(d,null,function(i){M.core.actionmenu&&M.core.actionmenu.instance&&M.core.actionmenu.instance.hideMenu(t),i.instancename&&(c=i.instancename);var o=e.Node.create(''),u=e.Node.create('').set("innerHTML",M.util.get_string("edittitleinstructions","moodle")),f=e.Node.create('').setAttrs({value:c,autocomplete:"off","aria-describedby":"id_editinstructions",maxLength:"255"});o.appendChild(s.one(r.ACTIVITYICON).cloneNode()),o.appendChild(f),o.setData("anchor",p),a.insert(u,"before"),p.replace(o);var d="left";window.right_to_left()&&(d="right"),s.addClass(n.EDITINGTITLE),f.focus().select(),h=f.on("blur",this.edit_title_cancel,this,s,!1),this.edittitleevents.push(h),h=f.on("key",this.edit_title_cancel,"esc",this,s,!0),this.edittitleevents.push(h),h=o.on("submit",this.edit_title_submit,this,s,l),this.edittitleevents.push(h)}),this},edit_title_submit:function(t,n,i){t.preventDefault();var s=e.Lang.trim(n.one(r.ACTIVITYFORM+" "+r.ACTIVITYTITLE).get("value"));this.edit_title_clear(n);var o=this.add_spinner(n);if(s!==null&&s!==""&&s!==i){var u={"class":"resource",field:"updatetitle",title:s,id:e.Moodle.core_course.util.cm.getId(n)};this.send_request(u,o,function(e){e.instancename&&n.one(r.INSTANCENAME).setContent(e.instancename)})}},edit_title_cancel:function(e,t,n){n&&e.preventDefault(),this.edit_title_clear(t)},edit_title_clear:function(t){(new e.EventHandle(this.edittitleevents)).detach();var i=t.one(r.ACTIVITYFORM),s=t.one("#id_editinstructions");i&&i.replace(i.getData("anchor")),s&&s.remove(),t.removeClass(n.EDITINGTITLE),e.later(100,this,function(){t.one(r.EDITTITLE).focus()}),e.one("input[name=title]")||e.one("body").append('')},set_visibility_resource_ui:function(e){var t=e.element,n=t.one(r.HIDE),i=!0,s=!1;n||(n=t.one(r.SHOW),i=!1,s=!0),typeof e.visible!="undefined"&&(s=e.visible);if(i!==s){var o="hide";s&&(o="show"),this.handle_resource_dim(n,t,o)}}},{NAME:"course-resource-toolbox",ATTRS:{}}),M.course.resource_toolbox=null,M.course.init_resource_toolbox=function(e){return M.course.resource_toolbox=new u(e),M.course.resource_toolbox};var a=function(){a.superclass.constructor.apply(this,arguments)};e.extend(a,o,{initializer:function(){M.course.coursebase.register_module(this),e.delegate("click",this.toggle_highlight,r.PAGECONTENT,r.SECTIONLI+" "+r.HIGHLIGHT,this),e.delegate("click",this.toggle_hide_section,r.PAGECONTENT,r.SECTIONLI+" "+r.SHOWHIDE,this)},toggle_hide_section:function(t){t.preventDefault();var i=t.target.ancestor(M.course.format.get_section_selector(e)),s=t.target.ancestor("a",!0),o=s.one("img"),u=s.one("span"),a,f,l;i.hasClass(n.SECTIONHIDDENCLASS)?(i.removeClass(n.SECTIONHIDDENCLASS),a=1,f="show",l="hide"):(i.addClass(n.SECTIONHIDDENCLASS),a=0,f="hide",l="show");var c=M.util.get_string(l+"fromothers","format_"+this.get("format"));o.setAttrs({alt:c,src:M.util.image_url("i/"+l)}),s.set("title",c),u&&u.set("text",c);var h={"class":"section",field:"visible",id:e.Moodle.core_course.util.section.getId(i.ancestor(M.course.format.get_section_wrapper(e),!0)),value:a},p=M.util.add_lightbox(e,i);p.show(),this.send_request(h,p,function(t){var n=i.all(r.ACTIVITYLI);n.each(function(n){var i;n.one(r.SHOW)?i=n.one(r.SHOW):i=n.one(r.HIDE);var s=e.Moodle.core_course.util.cm.getId(n);e.Array.indexOf(t.resourcestotoggle,""+s)!==-1&&M.course.resource_toolbox.handle_resource_dim(i,n,f)},this)})},toggle_highlight:function(t){t.preventDefault();var n=t.target.ancestor(M.course.format.get_section_selector(e)),i=t.target.ancestor("a",!0),s=i.one("img"),o=i.one("span"),u=n.hasClass("current"),a=0,f=M.util.get_string("markthistopic","moodle"),l=e.one(r.PAGECONTENT);l.all(M.course.format.get_section_selector(e)+".current "+r.HIGHLIGHT).set("title",f),l.all(M.course.format.get_section_selector(e)+".current "+r.HIGHLIGHT+" span").set("text",M.util.get_string("highlight","moodle")),l.all(M.course.format.get_section_selector(e)+".current "+r.HIGHLIGHT+" img").set("alt",f).set("src",M.util.image_url("i/marker")),l.all(M.course.format.get_section_selector(e)).removeClass("current");if(!u){n.addClass("current"),a=e.Moodle.core_course.util.section.getId(n.ancestor(M.course.format.get_section_wrapper(e),!0));var c=M.util.get_string("markedthistopic","moodle");i.set("title",c),s.set("alt",c).set("src",M.util.image_url("i/marked")),o&&o.set("text",M.util.get_string("highlightoff","moodle"))}var h={"class":"course",field:"marker",value
-:a},p=M.util.add_lightbox(e,n);p.show(),this.send_request(h,p)}},{NAME:"course-section-toolbox",ATTRS:{}}),M.course.init_section_toolbox=function(e){return new a(e)}},"@VERSION@",{requires:["node","base","event-key","node","io","moodle-course-coursebase","moodle-course-util"]});
+YUI.add("moodle-course-toolboxes",function(e,t){var n={ACTIVITYINSTANCE:"activityinstance",AVAILABILITYINFODIV:"div.availabilityinfo",CONTENTWITHOUTLINK:"contentwithoutlink",CONDITIONALHIDDEN:"conditionalhidden",DIMCLASS:"dimmed",DIMMEDTEXT:"dimmed_text",EDITINSTRUCTIONS:"editinstructions",HIDE:"hide",MODINDENTCOUNT:"mod-indent-",MODINDENTHUGE:"mod-indent-huge",MODULEIDPREFIX:"module-",SECTIONHIDDENCLASS:"hidden",SECTIONIDPREFIX:"section-",SHOW:"editing_show"},r={ACTIONAREA:".actions",ACTIONLINKTEXT:".actionlinktext",ACTIVITYACTION:"a.cm-edit-action[data-action]",ACTIVITYICON:"img.activityicon",ACTIVITYINSTANCE:"."+n.ACTIVITYINSTANCE,ACTIVITYLINK:"."+n.ACTIVITYINSTANCE+" > a, ."+n.ACTIVITYINSTANCE+" > span[data-inplaceeditable] > a:not([data-inplaceeditablelink])",ACTIVITYLI:"li.activity",COMMANDSPAN:".commands",CONTENTAFTERLINK:"div.contentafterlink",CONTENTWITHOUTLINK:"div.contentwithoutlink",GROUPINGLABEL:"."+n.ACTIVITYINSTANCE+" .groupinglabel",HIDE:"a.editing_hide",HIGHLIGHT:"a.editing_highlight",INSTANCENAME:"span.instancename",MODINDENTDIV:".mod-indent",MODINDENTOUTER:".mod-indent-outer",PAGECONTENT:"body",SECTIONLI:"li.section",SHOW:"a."+n.SHOW,SHOWHIDE:"a.editing_showhide"},i={MIN:0,MAX:16},s=e.one(document.body);M.course=M.course||{};var o=function(){o.superclass.constructor.apply(this,arguments)};e.extend(o,e.Base,{send_request:function(t,n,r,i){t||(t={});var s=this.get("config").pageparams,o;for(o in s)t[o]=s[o];t.sesskey=M.cfg.sesskey,t.courseId=this.get("courseid");var u=M.cfg.wwwroot+this.get("ajaxurl"),a=[],f={method:"POST",data:t,on:{success:function(t,i){try{a=e.JSON.parse(i.responseText),a.error&&new M.core.ajaxException(a)}catch(s){}r&&e.bind(r,this,a)(),n&&window.setTimeout(function(){n.hide()},400)},failure:function(e,t){n&&n.hide(),new M.core.ajaxException(t)}},context:this};if(i)for(o in i)f[o]=i[o];return n&&n.show(),e.io(u,f),this}},{NAME:"course-toolbox",ATTRS:{courseid:{value:0},format:{value:"topics"},ajaxurl:{value:null},config:{value:{}}}});var u=function(){u.superclass.constructor.apply(this,arguments)};e.extend(u,o,{GROUPS_NONE:0,GROUPS_SEPARATE:1,GROUPS_VISIBLE:2,initializer:function(){M.course.coursebase.register_module(this),s.delegate("key",this.handle_data_action,"down:enter",r.ACTIVITYACTION,this),e.delegate("click",this.handle_data_action,s,r.ACTIVITYACTION,this)},handle_data_action:function(e){var t=e.target;t.test("a")||(t=t.ancestor(r.ACTIVITYACTION));var n=t.getData("action"),i=t.ancestor(r.ACTIVITYLI);if(!t.test("a")||!n||!i)return;switch(n){case"moveleft":case"moveright":this.change_indent(e,t,i,n);break;case"delete":this.delete_with_confirmation(e,t,i,n);break;case"duplicate":this.duplicate(e,t,i,n);break;case"hide":case"show":this.change_visibility(e,t,i,n);break;case"groupsseparate":case"groupsvisible":case"groupsnone":this.change_groupmode(e,t,i,n);break;case"move":case"update":case"duplicate":case"assignroles":break;default:}},add_spinner:function(t){var n=t.one(r.ACTIONAREA);return n?M.util.add_spinner(e,n):null},change_indent:function(t,s,o,u){t.preventDefault();var a=u==="moveleft"?-1:1,f=o.one(r.MODINDENTDIV),l=f.getAttribute("class").match(/mod-indent-(\d{1,})/),c=0,h;l&&(c=parseInt(l[1],10)),h=c+parseInt(a,10);if(hi.MAX)return;l&&f.removeClass(l[0]),f.addClass(n.MODINDENTCOUNT+h);var p={"class":"resource",field:"indent",value:h,id:e.Moodle.core_course.util.cm.getId(o)},d=this.add_spinner(o);this.send_request(p,d);var v;h===i.MIN?(s.addClass("hidden"),v=o.one(".editing_moveright")):h>i.MIN&&c===i.MIN&&s.ancestor(".menu").one("[data-action=moveleft]").removeClass("hidden"),h===i.MAX?(s.addClass("hidden"),v=o.one(".editing_moveleft")):h15&&!m?f.addClass(n.MODINDENTHUGE):h<=15&&m&&f.removeClass(n.MODINDENTHUGE),t.type&&t.type==="key"&&v&&v.focus()},delete_with_confirmation:function(t,n,r){t.preventDefault();var i=r,s="",o={type:M.util.get_string("pluginname",i.getAttribute("class").match(/modtype_([^\s]*)/)[1])};e.Moodle.core_course.util.cm.getName(i)!==null?(o.name=e.Moodle.core_course.util.cm.getName(i),s=M.util.get_string("deletechecktypename","moodle",o)):s=M.util.get_string("deletechecktype","moodle",o);var u=new M.core.confirm({question:s,modal:!0,visible:!1});return u.show(),u.on("complete-yes",function(){i.remove();var n={"class":"resource",action:"DELETE",id:e.Moodle.core_course.util.cm.getId(i)};this.send_request(n),M.core.actionmenu&&M.core.actionmenu.instance&&M.core.actionmenu.instance.hideMenu(t)},this),this},duplicate:function(t,n,r){t.preventDefault();var i=r,s=r.ancestor(M.course.format.get_section_selector(e)),o=M.util.add_lightbox(e,s).show(),u={"class":"resource",field:"duplicate",id:e.Moodle.core_course.util.cm.getId(i),sr:n.getData("sr")};return this.send_request(u,o,function(t){var n=e.Node.create(t.fullcontent);r.insert(n,"after"),e.use("moodle-course-coursebase",function(){M.course.coursebase.invoke_function("setup_for_resource",n)}),M.core.actionmenu&&M.core.actionmenu.newDOMNode&&M.core.actionmenu.newDOMNode(n)}),this},change_visibility:function(t,n,r,i){t.preventDefault();var s=r,o=this.handle_resource_dim(n,r,i),u={"class":"resource",field:"visible",value:o,id:e.Moodle.core_course.util.cm.getId(s)},a=this.add_spinner(s);return this.send_request(u,a),this},handle_resource_dim:function(t,i,s){var o=n.DIMCLASS,u=i.one([r.ACTIVITYLINK,r.CONTENTWITHOUTLINK].join(", ")),a=i.one(n.AVAILABILITYINFODIV),f=s==="hide"?"show":"hide",l=t.one("span"),c=M.util.get_string(f,"moodle"),h=t.one("img");return h.setAttrs({src:M.util.image_url("t/"+f)}),e.Lang.trim(t.getAttribute("title"))&&t.setAttribute("title",c),e.Lang.trim(h.getAttribute("alt"))&&h.setAttribute("alt",c),t.replaceClass("editing_"+s,"editing_"+f),t.setData("action",f),l&&l.set("text",c),i.one(r.CONTENTWITHOUTLINK)&&(u=i.one(r.CONTENTWITHOUTLINK),o=n.DIMMEDTEXT),u.hasClass(n.CONDITIONALHIDDEN)||(s==="hide"?(u.addClass(o),i.all
+(r.CONTENTAFTERLINK).addClass(n.DIMMEDTEXT),i.all(r.GROUPINGLABEL).addClass(n.DIMMEDTEXT)):(u.removeClass(o),i.all(r.CONTENTAFTERLINK).removeClass(n.DIMMEDTEXT),i.all(r.GROUPINGLABEL).removeClass(n.DIMMEDTEXT))),a&&a.toggleClass(n.HIDE),s==="hide"?0:1},change_groupmode:function(t,n,r){t.preventDefault();var i=parseInt(n.getData("nextgroupmode"),10),s="",o="",u,a,f,l=i+1,c=n.one("img");l>2&&(l=0),i===this.GROUPS_NONE?(s="groupsnone",o=M.util.image_url("i/groupn","moodle")):i===this.GROUPS_SEPARATE?(s="groupsseparate",o=M.util.image_url("i/groups","moodle")):i===this.GROUPS_VISIBLE&&(s="groupsvisible",o=M.util.image_url("i/groupv","moodle")),u=M.util.get_string("clicktochangeinbrackets","moodle",M.util.get_string(s,"moodle"));var h=n.getData("action");return n.replaceClass("editing_"+h,"editing_"+s),c.setAttrs({src:o}),e.Lang.trim(n.getAttribute("title"))&&n.setAttribute("title",u).setData("action",s).setData("nextgroupmode",l),e.Lang.trim(c.getAttribute("alt"))&&c.setAttribute("alt",u),a={"class":"resource",field:"groupmode",value:i,id:e.Moodle.core_course.util.cm.getId(r)},f=this.add_spinner(r),this.send_request(a,f),this},set_visibility_resource_ui:function(e){var t=e.element,n=t.one(r.HIDE),i=!0,s=!1;n||(n=t.one(r.SHOW),i=!1,s=!0),typeof e.visible!="undefined"&&(s=e.visible);if(i!==s){var o="hide";s&&(o="show"),this.handle_resource_dim(n,t,o)}}},{NAME:"course-resource-toolbox",ATTRS:{}}),M.course.resource_toolbox=null,M.course.init_resource_toolbox=function(e){return M.course.resource_toolbox=new u(e),M.course.resource_toolbox};var a=function(){a.superclass.constructor.apply(this,arguments)};e.extend(a,o,{initializer:function(){M.course.coursebase.register_module(this),e.delegate("click",this.toggle_highlight,r.PAGECONTENT,r.SECTIONLI+" "+r.HIGHLIGHT,this),e.delegate("click",this.toggle_hide_section,r.PAGECONTENT,r.SECTIONLI+" "+r.SHOWHIDE,this)},toggle_hide_section:function(t){t.preventDefault();var i=t.target.ancestor(M.course.format.get_section_selector(e)),s=t.target.ancestor("a",!0),o=s.one("img"),u=s.one("span"),a,f,l;i.hasClass(n.SECTIONHIDDENCLASS)?(i.removeClass(n.SECTIONHIDDENCLASS),a=1,f="show",l="hide"):(i.addClass(n.SECTIONHIDDENCLASS),a=0,f="hide",l="show");var c=M.util.get_string(l+"fromothers","format_"+this.get("format"));o.setAttrs({alt:c,src:M.util.image_url("i/"+l)}),s.set("title",c),u&&u.set("text",c);var h={"class":"section",field:"visible",id:e.Moodle.core_course.util.section.getId(i.ancestor(M.course.format.get_section_wrapper(e),!0)),value:a},p=M.util.add_lightbox(e,i);p.show(),this.send_request(h,p,function(t){var n=i.all(r.ACTIVITYLI);n.each(function(n){var i;n.one(r.SHOW)?i=n.one(r.SHOW):i=n.one(r.HIDE);var s=e.Moodle.core_course.util.cm.getId(n);e.Array.indexOf(t.resourcestotoggle,""+s)!==-1&&M.course.resource_toolbox.handle_resource_dim(i,n,f)},this)})},toggle_highlight:function(t){t.preventDefault();var n=t.target.ancestor(M.course.format.get_section_selector(e)),i=t.target.ancestor("a",!0),s=i.one("img"),o=i.one("span"),u=n.hasClass("current"),a=0,f=M.util.get_string("markthistopic","moodle"),l=e.one(r.PAGECONTENT);l.all(M.course.format.get_section_selector(e)+".current "+r.HIGHLIGHT).set("title",f),l.all(M.course.format.get_section_selector(e)+".current "+r.HIGHLIGHT+" span").set("text",M.util.get_string("highlight","moodle")),l.all(M.course.format.get_section_selector(e)+".current "+r.HIGHLIGHT+" img").set("alt",f).set("src",M.util.image_url("i/marker")),l.all(M.course.format.get_section_selector(e)).removeClass("current");if(!u){n.addClass("current"),a=e.Moodle.core_course.util.section.getId(n.ancestor(M.course.format.get_section_wrapper(e),!0));var c=M.util.get_string("markedthistopic","moodle");i.set("title",c),s.set("alt",c).set("src",M.util.image_url("i/marked")),o&&o.set("text",M.util.get_string("highlightoff","moodle"))}var h={"class":"course",field:"marker",value:a},p=M.util.add_lightbox(e,n);p.show(),this.send_request(h,p)}},{NAME:"course-section-toolbox",ATTRS:{}}),M.course.init_section_toolbox=function(e){return new a(e)}},"@VERSION@",{requires:["node","base","event-key","node","io","moodle-course-coursebase","moodle-course-util"]});
diff --git a/course/yui/build/moodle-course-toolboxes/moodle-course-toolboxes.js b/course/yui/build/moodle-course-toolboxes/moodle-course-toolboxes.js
index 03d72a6199038..75ef3b8772fc4 100644
--- a/course/yui/build/moodle-course-toolboxes/moodle-course-toolboxes.js
+++ b/course/yui/build/moodle-course-toolboxes/moodle-course-toolboxes.js
@@ -19,31 +19,28 @@ var CSS = {
DIMCLASS : 'dimmed',
DIMMEDTEXT : 'dimmed_text',
EDITINSTRUCTIONS : 'editinstructions',
- EDITINGTITLE: 'editor_displayed',
HIDE : 'hide',
MODINDENTCOUNT : 'mod-indent-',
MODINDENTHUGE : 'mod-indent-huge',
MODULEIDPREFIX : 'module-',
SECTIONHIDDENCLASS : 'hidden',
SECTIONIDPREFIX : 'section-',
- SHOW : 'editing_show',
- TITLEEDITOR : 'titleeditor'
+ SHOW : 'editing_show'
},
// The CSS selectors we use.
SELECTOR = {
ACTIONAREA: '.actions',
ACTIONLINKTEXT : '.actionlinktext',
- ACTIVITYACTION : 'a.cm-edit-action[data-action], a.editing_title',
- ACTIVITYFORM : '.' + CSS.ACTIVITYINSTANCE + ' form',
+ ACTIVITYACTION : 'a.cm-edit-action[data-action]',
ACTIVITYICON : 'img.activityicon',
ACTIVITYINSTANCE : '.' + CSS.ACTIVITYINSTANCE,
- ACTIVITYLINK: '.' + CSS.ACTIVITYINSTANCE + ' > a',
+ ACTIVITYLINK: '.' + CSS.ACTIVITYINSTANCE + ' > a, .'+ CSS.ACTIVITYINSTANCE +
+ ' > span[data-inplaceeditable] > a:not([data-inplaceeditablelink])',
ACTIVITYLI : 'li.activity',
- ACTIVITYTITLE : 'input[name=title]',
COMMANDSPAN : '.commands',
CONTENTAFTERLINK : 'div.contentafterlink',
CONTENTWITHOUTLINK : 'div.contentwithoutlink',
- EDITTITLE: 'a.editing_title',
+ GROUPINGLABEL: '.' + CSS.ACTIVITYINSTANCE + ' .groupinglabel',
HIDE : 'a.editing_hide',
HIGHLIGHT : 'a.editing_highlight',
INSTANCENAME : 'span.instancename',
@@ -256,17 +253,6 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
*/
GROUPS_VISIBLE: 2,
- /**
- * An Array of events added when editing a title.
- * These should all be detached when editing is complete.
- *
- * @property edittitleevents
- * @protected
- * @type Array
- * @protected
- */
- edittitleevents: [],
-
/**
* Initialize the resource toolbox
*
@@ -317,10 +303,6 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
// Switch based upon the action and do the desired thing.
switch (action) {
- case 'edittitle':
- // The user wishes to edit the title of the event.
- this.edit_title(ev, node, activity, action);
- break;
case 'moveleft':
case 'moveright':
// The user changing the indent of the activity.
@@ -633,11 +615,13 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
dimarea.addClass(toggleclass);
// We need to toggle dimming on the description too.
activity.all(SELECTOR.CONTENTAFTERLINK).addClass(CSS.DIMMEDTEXT);
+ activity.all(SELECTOR.GROUPINGLABEL).addClass(CSS.DIMMEDTEXT);
} else {
// Change the UI.
dimarea.removeClass(toggleclass);
// We need to toggle dimming on the description too.
activity.all(SELECTOR.CONTENTAFTERLINK).removeClass(CSS.DIMMEDTEXT);
+ activity.all(SELECTOR.GROUPINGLABEL).removeClass(CSS.DIMMEDTEXT);
}
}
// Toggle availablity info for conditional activities.
@@ -714,172 +698,6 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
return this;
},
- /**
- * Edit the title for the resource
- *
- * @method edit_title
- * @protected
- * @param {EventFacade} ev The event that was fired.
- * @param {Node} button The button that triggered this action.
- * @param {Node} activity The activity node that this action will be performed on.
- * @param {String} action The action that has been requested.
- * @chainable
- */
- edit_title: function(ev, button, activity) {
- // Get the element we're working on
- var activityid = Y.Moodle.core_course.util.cm.getId(activity),
- instancename = activity.one(SELECTOR.INSTANCENAME),
- instance = activity.one(SELECTOR.ACTIVITYINSTANCE),
- currenttitle = instancename.get('firstChild'),
- oldtitle = currenttitle.get('data'),
- titletext = oldtitle,
- thisevent,
- anchor = instancename.ancestor('a'),// Grab the anchor so that we can swap it with the edit form.
- data = {
- 'class': 'resource',
- 'field': 'gettitle',
- 'id': activityid
- };
-
- // Prevent the default actions.
- ev.preventDefault();
-
- this.send_request(data, null, function(response) {
- if (M.core.actionmenu && M.core.actionmenu.instance) {
- M.core.actionmenu.instance.hideMenu(ev);
- }
-
- // Try to retrieve the existing string from the server
- if (response.instancename) {
- titletext = response.instancename;
- }
-
- // Create the editor and submit button
- var editform = Y.Node.create('');
- var editinstructions = Y.Node.create('')
- .set('innerHTML', M.util.get_string('edittitleinstructions', 'moodle'));
- var editor = Y.Node.create('').setAttrs({
- 'value': titletext,
- 'autocomplete': 'off',
- 'aria-describedby': 'id_editinstructions',
- 'maxLength': '255'
- });
-
- // Clear the existing content and put the editor in
- editform.appendChild(activity.one(SELECTOR.ACTIVITYICON).cloneNode());
- editform.appendChild(editor);
- editform.setData('anchor', anchor);
- instance.insert(editinstructions, 'before');
- anchor.replace(editform);
-
- // Force the editing instruction to match the mod-indent position.
- var padside = 'left';
- if (window.right_to_left()) {
- padside = 'right';
- }
-
- // We hide various components whilst editing:
- activity.addClass(CSS.EDITINGTITLE);
-
- // Focus and select the editor text
- editor.focus().select();
-
- // Cancel the edit if we lose focus or the escape key is pressed.
- thisevent = editor.on('blur', this.edit_title_cancel, this, activity, false);
- this.edittitleevents.push(thisevent);
- thisevent = editor.on('key', this.edit_title_cancel, 'esc', this, activity, true);
- this.edittitleevents.push(thisevent);
-
- // Handle form submission.
- thisevent = editform.on('submit', this.edit_title_submit, this, activity, oldtitle);
- this.edittitleevents.push(thisevent);
- });
- return this;
- },
-
- /**
- * Handles the submit event when editing the activity or resources title.
- *
- * @method edit_title_submit
- * @protected
- * @param {EventFacade} ev The event that triggered this.
- * @param {Node} activity The activity whose title we are altering.
- * @param {String} originaltitle The original title the activity or resource had.
- */
- edit_title_submit: function(ev, activity, originaltitle) {
- // We don't actually want to submit anything
- ev.preventDefault();
-
- var newtitle = Y.Lang.trim(activity.one(SELECTOR.ACTIVITYFORM + ' ' + SELECTOR.ACTIVITYTITLE).get('value'));
- this.edit_title_clear(activity);
- var spinner = this.add_spinner(activity);
- if (newtitle !== null && newtitle !== "" && newtitle !== originaltitle) {
- var data = {
- 'class': 'resource',
- 'field': 'updatetitle',
- 'title': newtitle,
- 'id': Y.Moodle.core_course.util.cm.getId(activity)
- };
- this.send_request(data, spinner, function(response) {
- if (response.instancename) {
- activity.one(SELECTOR.INSTANCENAME).setContent(response.instancename);
- }
- });
- }
- },
-
- /**
- * Handles the cancel event when editing the activity or resources title.
- *
- * @method edit_title_cancel
- * @protected
- * @param {EventFacade} ev The event that triggered this.
- * @param {Node} activity The activity whose title we are altering.
- * @param {Boolean} preventdefault If true we should prevent the default action from occuring.
- */
- edit_title_cancel: function(ev, activity, preventdefault) {
- if (preventdefault) {
- ev.preventDefault();
- }
- this.edit_title_clear(activity);
- },
-
- /**
- * Handles clearing the editing UI and returning things to the original state they were in.
- *
- * @method edit_title_clear
- * @protected
- * @param {Node} activity The activity whose title we were altering.
- */
- edit_title_clear: function(activity) {
- // Detach all listen events to prevent duplicate triggers
- new Y.EventHandle(this.edittitleevents).detach();
-
- var editform = activity.one(SELECTOR.ACTIVITYFORM),
- instructions = activity.one('#id_editinstructions');
- if (editform) {
- editform.replace(editform.getData('anchor'));
- }
- if (instructions) {
- instructions.remove();
- }
-
- // Remove the editing class again to revert the display.
- activity.removeClass(CSS.EDITINGTITLE);
-
- // Refocus the link which was clicked originally so the user can continue using keyboard nav.
- Y.later(100, this, function() {
- activity.one(SELECTOR.EDITTITLE).focus();
- });
-
- // TODO MDL-50768 This hack is to keep Behat happy until they release a version of
- // MinkSelenium2Driver that fixes
- // https://github.com/Behat/MinkSelenium2Driver/issues/80.
- if (!Y.one('input[name=title]')) {
- Y.one('body').append('');
- }
- },
-
/**
* Set the visibility of the specified resource to match the visible parameter.
*
diff --git a/course/yui/src/toolboxes/js/resource.js b/course/yui/src/toolboxes/js/resource.js
index 578630e347af3..3bb4e600ff153 100644
--- a/course/yui/src/toolboxes/js/resource.js
+++ b/course/yui/src/toolboxes/js/resource.js
@@ -52,17 +52,6 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
*/
GROUPS_VISIBLE: 2,
- /**
- * An Array of events added when editing a title.
- * These should all be detached when editing is complete.
- *
- * @property edittitleevents
- * @protected
- * @type Array
- * @protected
- */
- edittitleevents: [],
-
/**
* Initialize the resource toolbox
*
@@ -113,10 +102,6 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
// Switch based upon the action and do the desired thing.
switch (action) {
- case 'edittitle':
- // The user wishes to edit the title of the event.
- this.edit_title(ev, node, activity, action);
- break;
case 'moveleft':
case 'moveright':
// The user changing the indent of the activity.
@@ -429,11 +414,13 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
dimarea.addClass(toggleclass);
// We need to toggle dimming on the description too.
activity.all(SELECTOR.CONTENTAFTERLINK).addClass(CSS.DIMMEDTEXT);
+ activity.all(SELECTOR.GROUPINGLABEL).addClass(CSS.DIMMEDTEXT);
} else {
// Change the UI.
dimarea.removeClass(toggleclass);
// We need to toggle dimming on the description too.
activity.all(SELECTOR.CONTENTAFTERLINK).removeClass(CSS.DIMMEDTEXT);
+ activity.all(SELECTOR.GROUPINGLABEL).removeClass(CSS.DIMMEDTEXT);
}
}
// Toggle availablity info for conditional activities.
@@ -510,172 +497,6 @@ Y.extend(RESOURCETOOLBOX, TOOLBOX, {
return this;
},
- /**
- * Edit the title for the resource
- *
- * @method edit_title
- * @protected
- * @param {EventFacade} ev The event that was fired.
- * @param {Node} button The button that triggered this action.
- * @param {Node} activity The activity node that this action will be performed on.
- * @param {String} action The action that has been requested.
- * @chainable
- */
- edit_title: function(ev, button, activity) {
- // Get the element we're working on
- var activityid = Y.Moodle.core_course.util.cm.getId(activity),
- instancename = activity.one(SELECTOR.INSTANCENAME),
- instance = activity.one(SELECTOR.ACTIVITYINSTANCE),
- currenttitle = instancename.get('firstChild'),
- oldtitle = currenttitle.get('data'),
- titletext = oldtitle,
- thisevent,
- anchor = instancename.ancestor('a'),// Grab the anchor so that we can swap it with the edit form.
- data = {
- 'class': 'resource',
- 'field': 'gettitle',
- 'id': activityid
- };
-
- // Prevent the default actions.
- ev.preventDefault();
-
- this.send_request(data, null, function(response) {
- if (M.core.actionmenu && M.core.actionmenu.instance) {
- M.core.actionmenu.instance.hideMenu(ev);
- }
-
- // Try to retrieve the existing string from the server
- if (response.instancename) {
- titletext = response.instancename;
- }
-
- // Create the editor and submit button
- var editform = Y.Node.create('');
- var editinstructions = Y.Node.create('')
- .set('innerHTML', M.util.get_string('edittitleinstructions', 'moodle'));
- var editor = Y.Node.create('').setAttrs({
- 'value': titletext,
- 'autocomplete': 'off',
- 'aria-describedby': 'id_editinstructions',
- 'maxLength': '255'
- });
-
- // Clear the existing content and put the editor in
- editform.appendChild(activity.one(SELECTOR.ACTIVITYICON).cloneNode());
- editform.appendChild(editor);
- editform.setData('anchor', anchor);
- instance.insert(editinstructions, 'before');
- anchor.replace(editform);
-
- // Force the editing instruction to match the mod-indent position.
- var padside = 'left';
- if (window.right_to_left()) {
- padside = 'right';
- }
-
- // We hide various components whilst editing:
- activity.addClass(CSS.EDITINGTITLE);
-
- // Focus and select the editor text
- editor.focus().select();
-
- // Cancel the edit if we lose focus or the escape key is pressed.
- thisevent = editor.on('blur', this.edit_title_cancel, this, activity, false);
- this.edittitleevents.push(thisevent);
- thisevent = editor.on('key', this.edit_title_cancel, 'esc', this, activity, true);
- this.edittitleevents.push(thisevent);
-
- // Handle form submission.
- thisevent = editform.on('submit', this.edit_title_submit, this, activity, oldtitle);
- this.edittitleevents.push(thisevent);
- });
- return this;
- },
-
- /**
- * Handles the submit event when editing the activity or resources title.
- *
- * @method edit_title_submit
- * @protected
- * @param {EventFacade} ev The event that triggered this.
- * @param {Node} activity The activity whose title we are altering.
- * @param {String} originaltitle The original title the activity or resource had.
- */
- edit_title_submit: function(ev, activity, originaltitle) {
- // We don't actually want to submit anything
- ev.preventDefault();
-
- var newtitle = Y.Lang.trim(activity.one(SELECTOR.ACTIVITYFORM + ' ' + SELECTOR.ACTIVITYTITLE).get('value'));
- this.edit_title_clear(activity);
- var spinner = this.add_spinner(activity);
- if (newtitle !== null && newtitle !== "" && newtitle !== originaltitle) {
- var data = {
- 'class': 'resource',
- 'field': 'updatetitle',
- 'title': newtitle,
- 'id': Y.Moodle.core_course.util.cm.getId(activity)
- };
- this.send_request(data, spinner, function(response) {
- if (response.instancename) {
- activity.one(SELECTOR.INSTANCENAME).setContent(response.instancename);
- }
- });
- }
- },
-
- /**
- * Handles the cancel event when editing the activity or resources title.
- *
- * @method edit_title_cancel
- * @protected
- * @param {EventFacade} ev The event that triggered this.
- * @param {Node} activity The activity whose title we are altering.
- * @param {Boolean} preventdefault If true we should prevent the default action from occuring.
- */
- edit_title_cancel: function(ev, activity, preventdefault) {
- if (preventdefault) {
- ev.preventDefault();
- }
- this.edit_title_clear(activity);
- },
-
- /**
- * Handles clearing the editing UI and returning things to the original state they were in.
- *
- * @method edit_title_clear
- * @protected
- * @param {Node} activity The activity whose title we were altering.
- */
- edit_title_clear: function(activity) {
- // Detach all listen events to prevent duplicate triggers
- new Y.EventHandle(this.edittitleevents).detach();
-
- var editform = activity.one(SELECTOR.ACTIVITYFORM),
- instructions = activity.one('#id_editinstructions');
- if (editform) {
- editform.replace(editform.getData('anchor'));
- }
- if (instructions) {
- instructions.remove();
- }
-
- // Remove the editing class again to revert the display.
- activity.removeClass(CSS.EDITINGTITLE);
-
- // Refocus the link which was clicked originally so the user can continue using keyboard nav.
- Y.later(100, this, function() {
- activity.one(SELECTOR.EDITTITLE).focus();
- });
-
- // TODO MDL-50768 This hack is to keep Behat happy until they release a version of
- // MinkSelenium2Driver that fixes
- // https://github.com/Behat/MinkSelenium2Driver/issues/80.
- if (!Y.one('input[name=title]')) {
- Y.one('body').append('');
- }
- },
-
/**
* Set the visibility of the specified resource to match the visible parameter.
*
diff --git a/course/yui/src/toolboxes/js/toolbox.js b/course/yui/src/toolboxes/js/toolbox.js
index 7fd7b3b6461af..e3f6c8a78332c 100644
--- a/course/yui/src/toolboxes/js/toolbox.js
+++ b/course/yui/src/toolboxes/js/toolbox.js
@@ -17,31 +17,28 @@ var CSS = {
DIMCLASS : 'dimmed',
DIMMEDTEXT : 'dimmed_text',
EDITINSTRUCTIONS : 'editinstructions',
- EDITINGTITLE: 'editor_displayed',
HIDE : 'hide',
MODINDENTCOUNT : 'mod-indent-',
MODINDENTHUGE : 'mod-indent-huge',
MODULEIDPREFIX : 'module-',
SECTIONHIDDENCLASS : 'hidden',
SECTIONIDPREFIX : 'section-',
- SHOW : 'editing_show',
- TITLEEDITOR : 'titleeditor'
+ SHOW : 'editing_show'
},
// The CSS selectors we use.
SELECTOR = {
ACTIONAREA: '.actions',
ACTIONLINKTEXT : '.actionlinktext',
- ACTIVITYACTION : 'a.cm-edit-action[data-action], a.editing_title',
- ACTIVITYFORM : '.' + CSS.ACTIVITYINSTANCE + ' form',
+ ACTIVITYACTION : 'a.cm-edit-action[data-action]',
ACTIVITYICON : 'img.activityicon',
ACTIVITYINSTANCE : '.' + CSS.ACTIVITYINSTANCE,
- ACTIVITYLINK: '.' + CSS.ACTIVITYINSTANCE + ' > a',
+ ACTIVITYLINK: '.' + CSS.ACTIVITYINSTANCE + ' > a, .'+ CSS.ACTIVITYINSTANCE +
+ ' > span[data-inplaceeditable] > a:not([data-inplaceeditablelink])',
ACTIVITYLI : 'li.activity',
- ACTIVITYTITLE : 'input[name=title]',
COMMANDSPAN : '.commands',
CONTENTAFTERLINK : 'div.contentafterlink',
CONTENTWITHOUTLINK : 'div.contentwithoutlink',
- EDITTITLE: 'a.editing_title',
+ GROUPINGLABEL: '.' + CSS.ACTIVITYINSTANCE + ' .groupinglabel',
HIDE : 'a.editing_hide',
HIGHLIGHT : 'a.editing_highlight',
INSTANCENAME : 'span.instancename',
diff --git a/lang/en/moodle.php b/lang/en/moodle.php
index 13641d5025d85..53c98f4a5abf7 100644
--- a/lang/en/moodle.php
+++ b/lang/en/moodle.php
@@ -1228,6 +1228,7 @@
$string['neverdeletelogs'] = 'Never delete logs';
$string['new'] = 'New';
$string['newaccount'] = 'New account';
+$string['newactivityname'] = 'New name for activity {$a}';
$string['newcourse'] = 'New course';
$string['newpassword'] = 'New password';
$string['newpassword_help'] = 'Enter a new password or leave blank to keep current password.';
diff --git a/lib/deprecatedlib.php b/lib/deprecatedlib.php
index 5b806b14705df..b787c16f1cdd7 100644
--- a/lib/deprecatedlib.php
+++ b/lib/deprecatedlib.php
@@ -4408,3 +4408,54 @@ function get_clam_error_code($returncode) {
$antivirus = \core\antivirus\manager::get_antivirus('clamav');
return $antivirus->get_clam_error_code($returncode);
}
+
+/**
+ * Returns the rename action.
+ *
+ * @deprecated since 3.1
+ * @param cm_info $mod The module to produce editing buttons for
+ * @param int $sr The section to link back to (used for creating the links)
+ * @return The markup for the rename action, or an empty string if not available.
+ */
+function course_get_cm_rename_action(cm_info $mod, $sr = null) {
+ global $COURSE, $OUTPUT;
+
+ static $str;
+ static $baseurl;
+
+ debugging('Function course_get_cm_rename_action() is deprecated. Please use inplace_editable ' .
+ 'https://docs.moodle.org/dev/Inplace_editable', DEBUG_DEVELOPER);
+
+ $modcontext = context_module::instance($mod->id);
+ $hasmanageactivities = has_capability('moodle/course:manageactivities', $modcontext);
+
+ if (!isset($str)) {
+ $str = get_strings(array('edittitle'));
+ }
+
+ if (!isset($baseurl)) {
+ $baseurl = new moodle_url('/course/mod.php', array('sesskey' => sesskey()));
+ }
+
+ if ($sr !== null) {
+ $baseurl->param('sr', $sr);
+ }
+
+ // AJAX edit title.
+ if ($mod->has_view() && $hasmanageactivities && course_ajax_enabled($COURSE) &&
+ (($mod->course == $COURSE->id) || ($mod->course == SITEID))) {
+ // we will not display link if we are on some other-course page (where we should not see this module anyway)
+ return html_writer::span(
+ html_writer::link(
+ new moodle_url($baseurl, array('update' => $mod->id)),
+ $OUTPUT->pix_icon('t/editstring', '', 'moodle', array('class' => 'iconsmall visibleifjs', 'title' => '')),
+ array(
+ 'class' => 'editing_title',
+ 'data-action' => 'edittitle',
+ 'title' => $str->edittitle,
+ )
+ )
+ );
+ }
+ return '';
+}
diff --git a/theme/upgrade.txt b/theme/upgrade.txt
index 05587d51fff36..47492e5f24dd9 100644
--- a/theme/upgrade.txt
+++ b/theme/upgrade.txt
@@ -11,6 +11,9 @@ information provided here is intended especially for theme designer.
* notification_problem.mustache => notification_error.mustache
* notification_message => notification_info
* notification_redirect => notification_warning
+* Method core_course_renderer::course_section_cm_name() is split into two methods, custom themes that override
+ this method must be modified or otherwise editing functionality may become broken. This method is now also used by
+ social activities block and site menu block to display activities names.
=== 3.0 ===