From 9f3015ecf828a543eb2745b0ba632c4b236f6cbe Mon Sep 17 00:00:00 2001 From: Ruslan Kabalin Date: Thu, 24 May 2012 11:20:57 +0100 Subject: [PATCH] MDL-32824: Make dragdrop work correctly with section titles/links Initially, the default section title was swapped within the course format javascript functions. Though some section titles may be custom and does not require swapping, in addition they may have links to single section view. This introduces some callback functions for define what needs to be done in sections libs and js files. --- course/format/renderer.php | 25 ++++++++++++++-------- course/format/topics/format.js | 27 ++++++++++++++++++++---- course/format/topics/lib.php | 21 +++++++++++++++++++ course/format/weeks/format.js | 32 +++++++++++++++++++++-------- course/format/weeks/lib.php | 21 +++++++++++++++++++ course/rest.php | 9 ++++++++ course/yui/coursebase/coursebase.js | 15 ++++++++++++++ course/yui/dragdrop/dragdrop.js | 18 +++++++++++++--- 8 files changed, 145 insertions(+), 23 deletions(-) diff --git a/course/format/renderer.php b/course/format/renderer.php index d969e8bc7c7..986cad95151 100644 --- a/course/format/renderer.php +++ b/course/format/renderer.php @@ -56,6 +56,21 @@ abstract class format_section_renderer_base extends plugin_renderer_base { */ abstract protected function page_title(); + /** + * Generate the section title + * + * @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) { + $title = get_section_name($course, $section); + if ($section->section != 0 && $course->coursedisplay == COURSE_DISPLAY_MULTIPAGE) { + $title = html_writer::link(course_get_url($course, $section->section), $title); + } + return $title; + } + /** * Generate the content to displayed on the right part of a section * before course modules are included @@ -106,7 +121,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base { * * @param stdClass $section The course_section entry from DB * @param stdClass $course The course entry from DB - * @param bool $onsectionpage true if being printed on a section page + * @param bool $onsectionpage true if being printed on a single-section page * @return string HTML to output. */ protected function section_header($section, $course, $onsectionpage) { @@ -115,7 +130,6 @@ abstract class format_section_renderer_base extends plugin_renderer_base { $o = ''; $currenttext = ''; $sectionstyle = ''; - $linktitle = false; if ($section->section != 0) { // Only in the non-general sections. @@ -124,7 +138,6 @@ abstract class format_section_renderer_base extends plugin_renderer_base { } else if ($course->marker == $section->section) { $sectionstyle = ' current'; } - $linktitle = ($course->coursedisplay == COURSE_DISPLAY_MULTIPAGE); } $o.= html_writer::start_tag('li', array('id' => 'section-'.$section->section, @@ -138,11 +151,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base { $o.= html_writer::start_tag('div', array('class' => 'content')); if (!$onsectionpage) { - $title = get_section_name($course, $section); - if ($linktitle) { - $title = html_writer::link(course_get_url($course, $section->section), $title); - } - $o.= $this->output->heading($title, 3, 'sectionname'); + $o.= $this->output->heading($this->section_title($section, $course), 3, 'sectionname'); } $o.= html_writer::start_tag('div', array('class' => 'summary')); diff --git a/course/format/topics/format.js b/course/format/topics/format.js index 218492df6d6..71e87972308 100644 --- a/course/format/topics/format.js +++ b/course/format/topics/format.js @@ -1,4 +1,4 @@ -// Javascript functions for course format +// Javascript functions for Topics course format M.course = M.course || {}; @@ -36,13 +36,32 @@ M.course.format.get_config = function() { M.course.format.swap_sections = function(Y, node1, node2) { var CSS = { COURSECONTENT : 'course-content', - LEFT : 'left', SECTIONADDMENUS : 'section_add_menus' }; var sectionlist = Y.Node.all('.'+CSS.COURSECONTENT+' '+M.course.format.get_section_selector(Y)); - // Swap left block - sectionlist.item(node1).one('.'+CSS.LEFT).swap(sectionlist.item(node2).one('.'+CSS.LEFT)); // Swap menus sectionlist.item(node1).one('.'+CSS.SECTIONADDMENUS).swap(sectionlist.item(node2).one('.'+CSS.SECTIONADDMENUS)); } + +/** + * Process sections after ajax response + * + * @param {YUI} Y YUI3 instance + * @param {array} response ajax response + * @param {string} sectionfrom first affected section + * @param {string} sectionto last affected section + * @return void + */ +M.course.format.process_sections = function(Y, sectionlist, response, sectionfrom, sectionto) { + var CSS = { + SECTIONNAME : 'sectionname' + }; + + if (response.action == 'move') { + // update titles in all affected sections + for (var i = sectionfrom; i <= sectionto; i++) { + sectionlist.item(i).one('.'+CSS.SECTIONNAME).setContent(response.sectiontitles[i]); + } + } +} diff --git a/course/format/topics/lib.php b/course/format/topics/lib.php index 710abaf318e..e8632fcab8b 100644 --- a/course/format/topics/lib.php +++ b/course/format/topics/lib.php @@ -80,3 +80,24 @@ function callback_topics_ajax_support() { $ajaxsupport->testedbrowsers = array('MSIE' => 6.0, 'Gecko' => 20061111, 'Safari' => 531, 'Chrome' => 6.0); return $ajaxsupport; } + +/** + * Callback function to do some action after section move + * + * @param stdClass $course The course entry from DB + * @return array This will be passed in ajax respose. + */ +function callback_topics_ajax_section_move($course) { + global $COURSE, $PAGE; + + $titles = array(); + rebuild_course_cache($course->id); + $modinfo = get_fast_modinfo($COURSE); + $renderer = $PAGE->get_renderer('format_topics'); + if ($renderer && ($sections = $modinfo->get_section_info_all())) { + foreach ($sections as $number => $section) { + $titles[$number] = $renderer->section_title($section, $course); + } + } + return array('sectiontitles' => $titles, 'action' => 'move'); +} diff --git a/course/format/weeks/format.js b/course/format/weeks/format.js index 28aed42aa42..28ec82a2b4f 100644 --- a/course/format/weeks/format.js +++ b/course/format/weeks/format.js @@ -1,4 +1,4 @@ -// Javascript functions for course format +// Javascript functions for Weeks course format M.course = M.course || {}; @@ -36,16 +36,32 @@ M.course.format.get_config = function() { M.course.format.swap_sections = function(Y, node1, node2) { var CSS = { COURSECONTENT : 'course-content', - LEFT : 'left', - SECTIONADDMENUS : 'section_add_menus', - WEEKDATES: 'weekdates' + SECTIONADDMENUS : 'section_add_menus' }; var sectionlist = Y.Node.all('.'+CSS.COURSECONTENT+' '+M.course.format.get_section_selector(Y)); - // Swap left block - sectionlist.item(node1).one('.'+CSS.LEFT).swap(sectionlist.item(node2).one('.'+CSS.LEFT)); // Swap menus sectionlist.item(node1).one('.'+CSS.SECTIONADDMENUS).swap(sectionlist.item(node2).one('.'+CSS.SECTIONADDMENUS)); - // Swap week dates - sectionlist.item(node1).one('.'+CSS.WEEKDATES).swap(sectionlist.item(node2).one('.'+CSS.WEEKDATES)); +} + +/** + * Process sections after ajax response + * + * @param {YUI} Y YUI3 instance + * @param {array} response ajax response + * @param {string} sectionfrom first affected section + * @param {string} sectionto last affected section + * @return void + */ +M.course.format.process_sections = function(Y, sectionlist, response, sectionfrom, sectionto) { + var CSS = { + SECTIONNAME : 'sectionname' + }; + + if (response.action == 'move') { + // update titles in all affected sections + for (var i = sectionfrom; i <= sectionto; i++) { + sectionlist.item(i).one('.'+CSS.SECTIONNAME).setContent(response.sectiontitles[i]); + } + } } diff --git a/course/format/weeks/lib.php b/course/format/weeks/lib.php index 9201c9e2d6f..6619622383b 100644 --- a/course/format/weeks/lib.php +++ b/course/format/weeks/lib.php @@ -102,3 +102,24 @@ function callback_weeks_ajax_support() { $ajaxsupport->testedbrowsers = array('MSIE' => 6.0, 'Gecko' => 20061111, 'Safari' => 531, 'Chrome' => 6.0); return $ajaxsupport; } + +/** + * Callback function to do some action after section move + * + * @param stdClass $course The course entry from DB + * @return array This will be passed in ajax respose. + */ +function callback_weeks_ajax_section_move($course) { + global $COURSE, $PAGE; + + $titles = array(); + rebuild_course_cache($course->id); + $modinfo = get_fast_modinfo($COURSE); + $renderer = $PAGE->get_renderer('format_weeks'); + if ($renderer && ($sections = $modinfo->get_section_info_all())) { + foreach ($sections as $number => $section) { + $titles[$number] = $renderer->section_title($section, $course); + } + } + return array('sectiontitles' => $titles, 'action' => 'move'); +} diff --git a/course/rest.php b/course/rest.php index 5152563ad92..6efd228db65 100644 --- a/course/rest.php +++ b/course/rest.php @@ -89,6 +89,15 @@ switch($requestmethod) { case 'move': move_section_to($course, $id, $value); + // See if format wants to do something about it + $libfile = $CFG->dirroot.'/course/format/'.$course->format.'/lib.php'; + $functionname = 'callback_'.$course->format.'_ajax_section_move'; + if (!function_exists($functionname) && file_exists($libfile)) { + require_once $libfile; + } + if (function_exists($functionname)) { + echo json_encode($functionname($course)); + } break; } rebuild_course_cache($course->id); diff --git a/course/yui/coursebase/coursebase.js b/course/yui/coursebase/coursebase.js index 3dbbf0bf0a8..b02c36263c0 100644 --- a/course/yui/coursebase/coursebase.js +++ b/course/yui/coursebase/coursebase.js @@ -68,6 +68,21 @@ YUI.add('moodle-course-coursebase', function(Y) { return null; } + /** + * Process sections after ajax response (should be defined in format.js) + * If some response is expected, we pass it over to format, as it knows better + * hot to process it. + * + * @param {YUI} Y YUI3 instance + * @param {NodeList} list of sections + * @param {array} response ajax response + * @param {string} sectionfrom first affected section + * @param {string} sectionto last affected section + * @return void + */ + M.course.format.process_sections = M.course.format.process_sections || function(Y, sectionlist, response, sectionfrom, sectionto) { + return null; + } /** * Get sections config for this format, for examples see function definition diff --git a/course/yui/dragdrop/dragdrop.js b/course/yui/dragdrop/dragdrop.js index 012355ece9f..b054ef68578 100644 --- a/course/yui/dragdrop/dragdrop.js +++ b/course/yui/dragdrop/dragdrop.js @@ -172,9 +172,16 @@ YUI.add('moodle-course-dragdrop', function(Y) { lightbox.show(); }, success: function(tid, response) { - window.setTimeout(function(e) { - lightbox.hide(); - }, 250); + // Update section titles, we can't simply swap them as + // they might have custom title + try { + var responsetext = Y.JSON.parse(response.responseText); + if (responsetext.error) { + new M.core.ajaxException(responsetext); + } + M.course.format.process_sections(Y, sectionlist, responsetext, loopstart, loopend); + } catch (e) {} + // Classic bubble sort algorithm is applied to the section // nodes between original drag node location and the new one. do { @@ -193,6 +200,11 @@ YUI.add('moodle-course-dragdrop', function(Y) { } loopend = loopend - 1; } while (swapped); + + // Finally, hide the lightbox + window.setTimeout(function(e) { + lightbox.hide(); + }, 250); }, failure: function(tid, response) { this.ajax_failure(response);