Skip to content

Commit

Permalink
course MDL-8369 Front page combo list is now restructured and exandab…
Browse files Browse the repository at this point in the history
…le by JavaScript

This patch also implements a course renderer.
  • Loading branch information
Sam Hemelryk committed May 27, 2010
1 parent e00a959 commit 24e27ac
Show file tree
Hide file tree
Showing 10 changed files with 292 additions and 7 deletions.
2 changes: 2 additions & 0 deletions course/info.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
print_error('coursehidden', '', $CFG->wwwroot .'/');
}

$PAGE->set_context($context);
$PAGE->set_pagelayout('course');
$PAGE->set_url('/course/info.php', array('id' => $course->id));
$PAGE->set_title(get_string("summaryof", "", $course->fullname));
$PAGE->set_heading('Course info');
Expand Down
61 changes: 61 additions & 0 deletions course/lib.php
Original file line number Diff line number Diff line change
Expand Up @@ -1856,6 +1856,67 @@ function make_categories_list(&$list, &$parents, $requiredcapability = '',
}
}

/**
* This function generates a structured array of courses and categories.
*
* The depth of categories is limited by $CFG->maxcategorydepth however there
* is no limit on the number of courses!
*
* Suitable for use with the course renderers course_category_tree method:
* $renderer = $PAGE->get_renderer('core','course');
* echo $renderer->course_category_tree(get_course_category_tree());
*
* @global moodle_database $DB
* @param int $id
* @param int $depth
*/
function get_course_category_tree($id = 0, $depth = 0) {
global $DB;
$viewhiddencats = has_capability('moodle/category:viewhiddencategories', get_context_instance(CONTEXT_SYSTEM));
$categories = get_child_categories($id);
$categoryids = array();
foreach ($categories as $key => &$category) {
if (!$category->visible && !$viewhiddencats) {
unset($categories[$key]);
continue;
}
$categoryids[$category->id] = $category;
if (empty($CFG->maxcategorydepth) || $depth <= $CFG->maxcategorydepth) {
list($category->categories, $subcategories) = get_course_category_tree($category->id, $depth+1);
$categoryids = array_merge($categoryids, $subcategories);
$category->courses = array();
}
}

if ($depth > 0) {
// This is a recursive call so return the required array
return array($categories, $categoryids);
}

// The depth is 0 this function has just been called so we can finish it off

list($ccselect, $ccjoin) = context_instance_preload_sql('c.id', CONTEXT_COURSE, 'ctx');
list($catsql, $catparams) = $DB->get_in_or_equal(array_keys($categoryids));
$sql = "SELECT
c.id,c.sortorder,c.visible,c.fullname,c.shortname,c.password,c.summary,c.guest,c.cost,c.currency,c.category
$ccselect
FROM {course} c
$ccjoin
WHERE c.category $catsql ORDER BY c.sortorder ASC";
if ($courses = $DB->get_records_sql($sql, $catparams)) {
// loop throught them
foreach ($courses as $course) {
if ($course->id == SITEID) {
continue;
}
context_instance_preload($course);
if (!empty($course->visible) || has_capability('moodle/course:viewhiddencourses', get_context_instance(CONTEXT_COURSE, $course->id))) {
$categoryids[$course->category]->courses[$course->id] = $course;
}
}
}
return $categories;
}

/**
* Recursive function to print out all the categories in a nice format
Expand Down
157 changes: 157 additions & 0 deletions course/renderer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
<?php

// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle. If not, see <http://www.gnu.org/licenses/>.

/**
* Renderer for use with the course section and all the goodness that falls
* within it.
*
* This renderer should contain methods useful to courses, and categories.
*
* @package moodlecore
* @copyright 2010 Sam Hemelryk
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/

/**
* The core course renderer
*
* Can be retrieved with the following:
* $renderer = $PAGE->get_renderer('core','course');
*/
class core_course_renderer extends plugin_renderer_base {

/**
* A cache of strings
* @var stdClass
*/
protected $strings;

/**
* Override the constructor so that we can initialise the string cache
*
* @param moodle_page $page
* @param string $target
*/
public function __construct(moodle_page $page, $target) {
$this->strings = new stdClass;
parent::__construct($page, $target);
}

/**
* Renderers a structured array of courses and categories into a nice
* XHTML tree structure.
*
* This method was designed initially to display the front page course/category
* combo view. The structure can be retrieved by get_course_category_tree()
*
* @param array $structure
* @return string
*/
public function course_category_tree(array $structure) {
$this->strings->allowguests = get_string('allowguests');
$this->strings->requireskey = get_string('requireskey');
$this->strings->summary = get_string('summary');

// 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', 'collapsed'));

// Start content generation
$content = html_writer::start_tag('div', array('class'=>'course_category_tree', 'id'=>$id));
foreach ($structure as $category) {
$content .= $this->course_category_tree_category($category);
}
$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');

// Return the course category tree HTML
return $content;
}

/**
* Renderers a category for use with course_category_tree
*
* @param array $category
* @param int $depth
* @return string
*/
protected function course_category_tree_category(stdClass $category, $depth=1) {
$content = '';
$hassubcategories = (count($category->categories)>0);
$hascourses = (count($category->courses)>0);
$classes = array('category');
if ($category->parent != 0) {
$classes[] = 'subcategory';
}
if ($hassubcategories || $hascourses) {
$classes[] = 'with_children';
if ($depth > 1) {
$classes[] = 'collapsed';
}
}
$content .= html_writer::start_tag('div', array('class'=>join(' ', $classes)));
$content .= html_writer::start_tag('div', array('class'=>'category_label'));
$content .= html_writer::link(new moodle_url('/course/category.php', array('id'=>$category->id)), $category->name, array('class'=>'category_link'));
$content .= html_writer::end_tag('div');
if ($hassubcategories) {
$content .= html_writer::start_tag('div', array('class'=>'subcategories'));
foreach ($category->categories as $subcategory) {
$content .= $this->course_category_tree_category($subcategory, $depth+1);
}
$content .= html_writer::end_tag('div');
}
if ($hascourses) {
$content .= html_writer::start_tag('div', array('class'=>'courses'));
$coursecount = 0;
foreach ($category->courses as $course) {
$classes = array('course');
$coursecount ++;
$classes[] = ($coursecount%2)?'odd':'even';
$content .= html_writer::start_tag('div', array('class'=>join(' ', $classes)));
$content .= html_writer::link(new moodle_url('/course/view.php', array('id'=>$course->id)), $course->fullname, array('class'=>'course_link'));
$content .= html_writer::start_tag('div', array('class'=>'course_info clearfix'));

if ($course->guest ) {
$image = html_writer::empty_tag('img', array('src'=>$this->output->pix_url('i/guest'), 'alt'=>$this->strings->allowguests, 'title'=>$this->strings->allowguests));
$content .= html_writer::tag('div', $image, array('class'=>'course_info_spacer'));
} else {
$content .= html_writer::tag('div', '', array('class'=>'course_info_spacer'));
}
if ($course->password) {
$image = html_writer::empty_tag('img', array('src'=>$this->output->pix_url('i/key'), 'alt'=>$this->strings->requireskey, 'title'=>$this->strings->requireskey));
$content .= html_writer::tag('div', $image, array('class'=>'course_info_spacer'));
} else {
$content .= html_writer::tag('div', '', array('class'=>'course_info_spacer'));
}
if ($course->summary) {
$image = html_writer::empty_tag('img', array('src'=>$this->output->pix_url('i/info'), 'alt'=>$this->strings->summary));
$content .= html_writer::link(new moodle_url('/course/info.php', array('id'=>$course->id)), $image, array('title'=>$this->strings->summary));
} else {
$content .= html_writer::tag('div', '', array('class'=>'course_info_spacer'));
}
$content .= html_writer::end_tag('div');
$content .= html_writer::end_tag('div');
}
$content .= html_writer::end_tag('div');
}
$content .= html_writer::end_tag('div');
return $content;
}
}
6 changes: 2 additions & 4 deletions index.php
Original file line number Diff line number Diff line change
Expand Up @@ -196,11 +196,9 @@
break;

case FRONTPAGECATEGORYCOMBO:

echo $OUTPUT->heading(get_string('categories'), 2, 'headingblock header');
echo $OUTPUT->box_start('generalbox categorybox');
print_whole_category_list(NULL, NULL, NULL, -1, true);
echo $OUTPUT->box_end();
$renderer = $PAGE->get_renderer('core','course');
echo $renderer->course_category_tree(get_course_category_tree());
print_course_search('', false, 'short');
break;

Expand Down
4 changes: 3 additions & 1 deletion lang/en/moodle.php
Original file line number Diff line number Diff line change
Expand Up @@ -250,6 +250,7 @@
$string['clicktohideshow'] = 'Click to expand or collapse';
$string['clicktochange'] = 'Click to change';
$string['closewindow'] = 'Close this window';
$string['collapseall'] = 'Collapse all';
$string['commentincontext'] = 'Find this comment in context';
$string['comments'] = 'Comments';
$string['comparelanguage'] = 'Compare and edit current language';
Expand Down Expand Up @@ -675,6 +676,7 @@
$string['existingcreators'] = 'Existing course creators';
$string['existingstudents'] = 'Enrolled students';
$string['existingteachers'] = 'Existing teachers';
$string['expandall'] = 'Expand all';
$string['expirynotify'] = 'Enrolment expiry notification';
$string['expirynotifyemail'] = 'The following students in this course are expiring after exactly {$a->threshold} days:
Expand Down Expand Up @@ -1903,4 +1905,4 @@
$string['yourself'] = 'yourself';
$string['yourteacher'] = 'your {$a}';
$string['yourwordforx'] = 'Your word for \'{$a}\'';
$string['zippingbackup'] = 'Zipping backup';
$string['zippingbackup'] = 'Zipping backup';
30 changes: 30 additions & 0 deletions lib/javascript-static.js
Original file line number Diff line number Diff line change
Expand Up @@ -393,6 +393,36 @@ M.util.init_frametop = function(Y) {
});
};

/**
* Finds all nodes that match the given CSS selector and attaches events to them
* so that they toggle a given classname when clicked.
*
* @param {YUI} Y
* @param {string} id An id containing elements to target
* @param {string} cssselector A selector to use to find targets
* @param {string} toggleclassname A classname to toggle
*/
M.util.init_toggle_class_on_click = function(Y, id, cssselector, toggleclassname) {
var node = Y.one('#'+id);
node.all(cssselector).each(function(node){
node.on('click', function(e){
e.stopPropagation();
if (e.target.get('nodeName')!='A' && e.target.get('nodeName')!='IMG') {
this.toggleClass(toggleclassname);
}
}, node);
});
// Attach this click event to the node rather than all selectors... will be much better
// for performance
node.on('click', function(e){
if (e.target.hasClass('addtoall')) {
node.all(cssselector).addClass(toggleclassname);
} else if (e.target.hasClass('removefromall')) {
node.all(cssselector+'.'+toggleclassname).removeClass(toggleclassname);
}
}, node);
}

//=== old legacy JS code, hopefully to be replaced soon by M.xx.yy and YUI3 code ===

function popupchecker(msg) {
Expand Down
1 change: 1 addition & 0 deletions lib/moodlelib.php
Original file line number Diff line number Diff line change
Expand Up @@ -7021,6 +7021,7 @@ function get_core_subsystems() {
'condition' => NULL,
'completion' => NULL,
'countries' => NULL,
'course' => 'course',
'currencies' => NULL,
'dbtransfer' => NULL,
'debug' => NULL,
Expand Down
1 change: 1 addition & 0 deletions mod/assignment/index.php
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
$PAGE->set_url('/mod/assignment/index.php', array('id'=>$course->id));
$PAGE->navbar->add($strassignments);
$PAGE->set_title($strassignments);
$PAGE->set_heading($course->fullname);
echo $OUTPUT->header();

if (!$cms = get_coursemodules_in_course('assignment', $course->id, 'cm.idnumber, m.assignmenttype, m.timedue')) {
Expand Down
17 changes: 16 additions & 1 deletion theme/base/style/course.css
Original file line number Diff line number Diff line change
Expand Up @@ -85,4 +85,19 @@
.weeks-format, /* Window-width: 800 pixels.IE doesn't support, see inline IE conditional comment. */
.topics-format {margin-top: 8px;min-width: 763px;}
#page-course-user .section {border-width:1px;border-style:solid;padding:10px;}
.categoryboxcontent {border-width:1px;border-style:solid;}
.categoryboxcontent {border-width:1px;border-style:solid;}

/* Course and category combo list on front page */
.course_category_tree .controls {visibility: hidden;}
.course_category_tree .controls div {display:inline;cursor:pointer;}
.course_category_tree .category.with_children .category_label {background-image:url([[pix:moodle|t/expanded]]);background-repeat: no-repeat;}
.course_category_tree .category_label {padding-left:13px;}
.course_category_tree .category .courses .course_link {display:block;background-image:url([[pix:moodle|i/course]]);background-repeat: no-repeat;padding-left:18px;}
.course_category_tree .category .course {position:relative;}
.course_category_tree .category .course_info {position:absolute;right:0;top:0;}
.course_category_tree .category .course_info a,
.course_category_tree .category .course_info div {float:left;width:16px;height:16px;}
.jsenabled .course_category_tree .controls {visibility: visible;}
.jsenabled .course_category_tree .category.with_children.collapsed .category_label {background-image:url([[pix:moodle|t/collapsed]]);}
.jsenabled .course_category_tree .category.with_children.collapsed .subcategories,
.jsenabled .course_category_tree .category.with_children.collapsed .courses {display:none;}
20 changes: 19 additions & 1 deletion theme/standard/style/course.css
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,22 @@
.addcoursebutton {text-align:center;}
.categorypicker {text-align:center;margin-bottom:10px;}
.path-course-report-outline .loginfo {text-align:center;margin: 1em;}
.categorylist {width: 90%;margin:0 auto;text-align: left;}
.categorylist {width: 90%;margin:0 auto;text-align: left;}

/* Course and category combo list on front page */
.course_category_tree .controls {margin-bottom:5px;text-align:right;float:right;}
.course_category_tree .controls div {padding-right:2em;font-size:75%;}
.course_category_tree .category {background-color:#FFF;background-image:url([[pix:theme|hgradient]]);background-repeat: repeat-x;border:1px solid #ddd;margin-bottom:10px;}
.course_category_tree .category .category {margin:5px;}
.course_category_tree .category .subcategories {background-color:inherit;padding-left:16px;border:1px solid #FFF;}
.course_category_tree .category.with_children .category_label {background-position:3px 3px;}
.course_category_tree .category_link .category_link {font-size:95%;}
.course_category_tree .category_label {padding-left:13px;}
.course_category_tree .category_link {display:block;margin:5px;font-size:120%;font-weight:bold;}
.course_category_tree .category .courses {background-color:inherit;padding-left:16px;}
.course_category_tree .category .courses .course_link {margin:5px;}
.course_category_tree .category .course {border:1px solid #f9f9f9;border-bottom-color: #eee;border-right-width:0;}
.course_category_tree .category .course:last-child {border-bottom-color:#f6f6f6;}
.course_category_tree .category .course.even {background-color:#f6f6f6;border-color:#eee;border-top-color: #f9f9f9;}
.course_category_tree .category .course_info {right:3px;top:3px;}
.course_category_tree .category .course:hover {background-color:#eee;}

0 comments on commit 24e27ac

Please sign in to comment.