MDL-38661 Course: Add JS category expander.

This adds a category expanded which:
* fetches child content in a category tree if it has not already been loaded;
* toggles relevant classes on the category node to show and hide child content; and
* applies appropriate animations to improve user experience.
This commit is contained in:
Andrew Robert Nicols 2013-03-12 11:27:45 +00:00 committed by Marina Glancy
parent b69ec2889e
commit 53c1b936e5
18 changed files with 1437 additions and 103 deletions

View file

@ -40,6 +40,9 @@ class core_course_renderer extends plugin_renderer_base {
const COURSECAT_SHOW_COURSES_EXPANDED = 20;
const COURSECAT_SHOW_COURSES_EXPANDED_WITH_CAT = 30;
const COURSECAT_TYPE_CATEGORY = 0;
const COURSECAT_TYPE_COURSE = 1;
/**
* A cache of strings
* @var stdClass
@ -1133,7 +1136,13 @@ class core_course_renderer extends plugin_renderer_base {
$classes .= ' collapsed';
$nametag = 'div';
}
$content .= html_writer::start_tag('div', array('class' => $classes)); // .coursebox
// .coursebox
$content .= html_writer::start_tag('div', array(
'class' => $classes,
'data-courseid' => $course->id,
'data-type' => self::COURSECAT_TYPE_COURSE,
));
$content .= html_writer::start_tag('div', array('class' => 'info'));
@ -1151,6 +1160,8 @@ class core_course_renderer extends plugin_renderer_base {
$image = html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/info'),
'alt' => $this->strings->summary));
$content .= html_writer::link($url, $image, array('title' => $this->strings->summary));
// Make sure JS file to expand course content is included.
$this->coursecat_include_js();
}
}
$content .= html_writer::end_tag('div'); // .moreinfo
@ -1418,6 +1429,20 @@ class core_course_renderer extends plugin_renderer_base {
return $content;
}
/**
* Make sure that javascript file for AJAX expanding of courses and categories content is included
*/
protected function coursecat_include_js() {
global $CFG;
static $jsloaded = false;
if (!$jsloaded && $CFG->enableajax) {
// We must only load this module once.
$this->page->requires->yui_module('moodle-course-categoryexpander',
'Y.Moodle.course.categoryexpander.init');
$jsloaded = true;
}
}
/**
* Returns HTML to display the subcategories and courses in the given category
*
@ -1490,6 +1515,8 @@ class core_course_renderer extends plugin_renderer_base {
$classes[] = 'with_children';
$classes[] = 'collapsed';
}
// Make sure JS file to expand category content is included.
$this->coursecat_include_js();
} else {
// load category content
$categorycontent = $this->coursecat_category_content($chelper, $coursecat, $depth);
@ -1498,9 +1525,13 @@ class core_course_renderer extends plugin_renderer_base {
$classes[] = 'with_children';
}
}
$content = html_writer::start_tag('div', array('class' => join(' ', $classes),
$content = html_writer::start_tag('div', array(
'class' => join(' ', $classes),
'data-categoryid' => $coursecat->id,
'data-depth' => $depth));
'data-depth' => $depth,
'data-showcourses' => $chelper->get_show_courses(),
'data-type' => self::COURSECAT_TYPE_CATEGORY,
));
// category name
$categoryname = $coursecat->get_formatted_name();
@ -1538,29 +1569,29 @@ class core_course_renderer extends plugin_renderer_base {
return '';
}
// Generate an id and the required JS call to make this a nice widget
$id = html_writer::random_id('course_category_tree');
$this->page->requires->js_init_call('M.util.init_toggle_class_on_click',
array($id, '.category.with_children.loaded > .info .name', 'collapsed', '.category.with_children.loaded'));
// Start content generation
$content = '';
$attributes = $chelper->get_and_erase_attributes('course_category_tree clearfix');
$content .= html_writer::start_tag('div',
array('id' => $id, 'data-showcourses' => $chelper->get_show_courses()) + $attributes);
$content .= html_writer::start_tag('div', $attributes);
if ($coursecat->get_children_count()) {
$classes = array(
'collapseexpand',
'collapse-all',
);
if ($chelper->get_subcat_depth() == 1) {
$classes[] = 'disabled';
}
// Only show the collapse/expand if there are children to expand.
$content .= html_writer::start_tag('div', array('class' => 'collapsible-actions'));
$content .= html_writer::link('#', get_string('collapseall'),
array('class' => implode(' ', $classes)));
$content .= html_writer::end_tag('div');
$this->page->requires->strings_for_js(array('collapseall', 'expandall'), 'moodle');
}
$content .= html_writer::tag('div', $categorycontent, array('class' => 'content'));
if ($coursecat->get_children_count() && $chelper->get_subcat_depth() != 1) {
// We don't need to display "Expand all"/"Collapse all" buttons if there are no
// subcategories or there is only one level of subcategories loaded
// TODO if subcategories are loaded by AJAX this might still be needed!
$content .= html_writer::start_tag('div', array('class' => 'controls'));
$content .= html_writer::tag('div', get_string('collapseall'), array('class' => 'addtoall expandall'));
$content .= html_writer::tag('div', get_string('expandall'), array('class' => 'removefromall collapseall'));
$content .= html_writer::end_tag('div');
}
$content .= html_writer::end_tag('div'); // .course_category_tree
return $content;
@ -1685,6 +1716,58 @@ class core_course_renderer extends plugin_renderer_base {
return $output;
}
/**
* Serves requests to /course/category.ajax.php
*
* In this renderer implementation it may expand the category content or
* course content.
*
* @return string
* @throws coding_exception
*/
public function coursecat_ajax() {
global $DB, $CFG;
require_once($CFG->libdir. '/coursecatlib.php');
$type = required_param('type', PARAM_INT);
if ($type === self::COURSECAT_TYPE_CATEGORY) {
// This is a request for a category list of some kind.
$categoryid = required_param('categoryid', PARAM_INT);
$showcourses = required_param('showcourses', PARAM_INT);
$depth = required_param('depth', PARAM_INT);
$category = coursecat::get($categoryid);
$chelper = new coursecat_helper();
$baseurl = new moodle_url('/course/index.php', array('categoryid' => $categoryid));
$coursedisplayoptions = array(
'limit' => $CFG->coursesperpage,
'viewmoreurl' => new moodle_url($baseurl, array('browse' => 'courses', 'page' => 1))
);
$catdisplayoptions = array(
'limit' => $CFG->coursesperpage,
'viewmoreurl' => new moodle_url($baseurl, array('browse' => 'categories', 'page' => 1))
);
$chelper->set_show_courses($showcourses)->
set_courses_display_options($coursedisplayoptions)->
set_categories_display_options($catdisplayoptions);
return $this->coursecat_category_content($chelper, $category, $depth);
} else if ($type === self::COURSECAT_TYPE_COURSE) {
// This is a request for the course information.
$courseid = required_param('courseid', PARAM_INT);
$course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST);
$chelper = new coursecat_helper();
$chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED);
return $this->coursecat_coursebox_content($chelper, $course);
} else {
throw new coding_exception('Invalid request type');
}
}
/**
* Renders html to display search result page
*