2 // This file is part of Moodle - http://moodle.org/
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
18 * Contains renderers for the course management pages.
20 * @package core_course
21 * @copyright 2013 Sam Hemelryk
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
25 defined('MOODLE_INTERNAL') ||
die;
27 require_once($CFG->dirroot
.'/course/renderer.php');
30 * Main renderer for the course management pages.
32 * @package core_course
33 * @copyright 2013 Sam Hemelryk
34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
36 class core_course_management_renderer
extends plugin_renderer_base
{
39 * Initialises the JS required to enhance the management interface.
41 * Thunderbirds are go, this function kicks into gear the JS that makes the
42 * course management pages that much cooler.
44 public function enhance_management_interface() {
45 $this->page
->requires
->yui_module('moodle-course-management', 'M.course.management.init');
46 $this->page
->requires
->strings_for_js(
65 * Displays a heading for the management pages.
67 * @param string $heading The heading to display
68 * @param string|null $viewmode The current view mode if there are options.
69 * @param int|null $categoryid The currently selected category if there is one.
72 public function management_heading($heading, $viewmode = null, $categoryid = null) {
73 $html = html_writer
::start_div('coursecat-management-header clearfix');
74 if (!empty($heading)) {
75 $html .= $this->heading($heading);
77 if ($viewmode !== null) {
78 $html .= html_writer
::start_div();
79 $html .= $this->view_mode_selector(\core_course\management\helper
::get_management_viewmodes(), $viewmode);
80 if ($viewmode === 'courses') {
81 $categories = coursecat
::make_categories_list(array('moodle/category:manage', 'moodle/course:create'));
83 if ($categoryid === null) {
84 $nothing = array('' => get_string('selectacategory'));
87 $select = new single_select($this->page
->url
, 'categoryid', $categories, $categoryid, $nothing);
88 $html .= $this->render($select);
90 $html .= html_writer
::end_div();
92 $html .= html_writer
::end_div();
97 * Prepares the form element for the course category listing bulk actions.
101 public function management_form_start() {
102 $form = array('action' => $this->page
->url
->out(), 'method' => 'POST', 'id' => 'coursecat-management');
104 $html = html_writer
::start_tag('form', $form);
105 $html .= html_writer
::empty_tag('input', array('type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey()));
106 $html .= html_writer
::empty_tag('input', array('type' => 'hidden', 'name' => 'action', 'value' => 'bulkaction'));
111 * Closes the course category bulk management form.
115 public function management_form_end() {
116 return html_writer
::end_tag('form');
120 * Presents a course category listing.
122 * @param coursecat $category The currently selected category. Also the category to highlight in the listing.
125 public function category_listing(coursecat
$category = null) {
127 if ($category === null) {
128 $selectedparents = array();
129 $selectedcategory = null;
131 $selectedparents = $category->get_parents();
132 $selectedparents[] = $category->id
;
133 $selectedcategory = $category->id
;
135 $catatlevel = \core_course\management\helper
::get_expanded_categories('');
136 $catatlevel[] = array_shift($selectedparents);
137 $catatlevel = array_unique($catatlevel);
139 $listing = coursecat
::get(0)->get_children();
144 'aria-labelledby' => 'category-listing-title'
147 $html = html_writer
::start_div('category-listing');
148 $html .= html_writer
::tag('h3', get_string('categories'), array('id' => 'category-listing-title'));
149 $html .= $this->category_listing_actions($category);
150 $html .= html_writer
::start_tag('ul', $attributes);
151 foreach ($listing as $listitem) {
152 // Render each category in the listing.
153 $subcategories = array();
154 if (in_array($listitem->id
, $catatlevel)) {
155 $subcategories = $listitem->get_children();
157 $html .= $this->category_listitem(
160 $listitem->get_children_count(),
165 $html .= html_writer
::end_tag('ul');
166 $html .= $this->category_bulk_actions($category);
167 $html .= html_writer
::end_div();
172 * Renders a category list item.
174 * This function gets called recursively to render sub categories.
176 * @param coursecat $category The category to render as listitem.
177 * @param coursecat[] $subcategories The subcategories belonging to the category being rented.
178 * @param int $totalsubcategories The total number of sub categories.
179 * @param int $selectedcategory The currently selected category
180 * @param int[] $selectedcategories The path to the selected category and its ID.
183 public function category_listitem(coursecat
$category, array $subcategories, $totalsubcategories,
184 $selectedcategory = null, $selectedcategories = array()) {
186 $isexpandable = ($totalsubcategories > 0);
187 $isexpanded = (!empty($subcategories));
188 $activecategory = ($selectedcategory === $category->id
);
190 'class' => 'listitem listitem-category',
191 'data-id' => $category->id
,
192 'data-expandable' => $isexpandable ?
'1' : '0',
193 'data-expanded' => $isexpanded ?
'1' : '0',
194 'data-selected' => $activecategory ?
'1' : '0',
195 'data-visible' => $category->visible ?
'1' : '0',
196 'role' => 'treeitem',
197 'aria-expanded' => $isexpanded ?
'true' : 'false'
199 $text = $category->get_formatted_name();
200 if ($category->parent
) {
202 $a->category
= $text;
203 $a->parentcategory
= $category->get_parent_coursecat()->get_formatted_name();
204 $textlabel = get_string('categorysubcategoryof', 'moodle', $a);
206 $courseicon = $this->output
->pix_icon('i/course', get_string('courses'));
208 'type' => 'checkbox',
210 'value' => $category->id
,
211 'class' => 'bulk-action-checkbox',
212 'aria-label' => get_string('bulkactionselect', 'moodle', $text),
213 'data-action' => 'select'
216 if (!$category->can_resort_subcategories() && !$category->has_manage_capability()) {
217 // Very very hardcoded here.
218 $bcatinput['style'] = 'visibility:hidden';
221 $viewcaturl = new moodle_url('/course/management.php', array('categoryid' => $category->id
));
223 $icon = $this->output
->pix_icon('t/switch_minus', get_string('collapse'), 'moodle', array('class' => 'tree-icon', 'title' => ''));
224 $icon = html_writer
::link(
228 'class' => 'float-left',
229 'data-action' => 'collapse',
230 'title' => get_string('collapsecategory', 'moodle', $text),
231 'aria-controls' => 'subcategoryof'.$category->id
234 } else if ($isexpandable) {
235 $icon = $this->output
->pix_icon('t/switch_plus', get_string('expand'), 'moodle', array('class' => 'tree-icon', 'title' => ''));
236 $icon = html_writer
::link(
240 'class' => 'float-left',
241 'data-action' => 'expand',
242 'title' => get_string('expandcategory', 'moodle', $text)
246 $icon = $this->output
->pix_icon(
250 array('class' => 'tree-icon', 'title' => get_string('showcategory', 'moodle', $text))
252 $icon = html_writer
::span($icon, 'float-left');
254 $actions = \core_course\management\helper
::get_category_listitem_actions($category);
255 $hasactions = !empty($actions) ||
$category->can_create_course();
257 $html = html_writer
::start_tag('li', $attributes);
258 $html .= html_writer
::start_div('clearfix');
259 $html .= html_writer
::start_div('float-left ba-checkbox');
260 $html .= html_writer
::empty_tag('input', $bcatinput).' ';
261 $html .= html_writer
::end_div();
264 $textattributes = array('class' => 'float-left categoryname');
266 $textattributes = array('class' => 'float-left categoryname without-actions');
268 if (isset($textlabel)) {
269 $textattributes['aria-label'] = $textlabel;
271 $html .= html_writer
::link($viewcaturl, $text, $textattributes);
272 $html .= html_writer
::start_div('float-right');
273 if ($category->idnumber
) {
274 $html .= html_writer
::tag('span', s($category->idnumber
), array('class' => 'dimmed idnumber'));
277 $html .= $this->category_listitem_actions($category, $actions);
279 $countid = 'course-count-'.$category->id
;
280 $html .= html_writer
::span(
281 html_writer
::span($category->get_courses_count()) .
282 html_writer
::span(get_string('courses'), 'accesshide', array('id' => $countid)) .
284 'course-count dimmed',
285 array('aria-labelledby' => $countid)
287 $html .= html_writer
::end_div();
288 $html .= html_writer
::end_div();
290 $html .= html_writer
::start_tag('ul',
291 array('class' => 'ml', 'role' => 'group', 'id' => 'subcategoryof'.$category->id
));
292 $catatlevel = \core_course\management\helper
::get_expanded_categories($category->path
);
293 $catatlevel[] = array_shift($selectedcategories);
294 $catatlevel = array_unique($catatlevel);
295 foreach ($subcategories as $listitem) {
296 $childcategories = (in_array($listitem->id
, $catatlevel)) ?
$listitem->get_children() : array();
297 $html .= $this->category_listitem(
300 $listitem->get_children_count(),
305 $html .= html_writer
::end_tag('ul');
307 $html .= html_writer
::end_tag('li');
312 * Renderers the actions that are possible for the course category listing.
314 * These are not the actions associated with an individual category listing.
315 * That happens through category_listitem_actions.
317 * @param coursecat $category
320 public function category_listing_actions(coursecat
$category = null) {
323 $cancreatecategory = $category && $category->can_create_subcategory();
324 $cancreatecategory = $cancreatecategory || coursecat
::can_create_top_level_category();
325 if ($category === null) {
326 $category = coursecat
::get(0);
329 if ($cancreatecategory) {
330 $url = new moodle_url('/course/editcategory.php', array('parent' => $category->id
));
331 $actions[] = html_writer
::link($url, get_string('createnewcategory'));
333 if (coursecat
::can_approve_course_requests()) {
334 $actions[] = html_writer
::link(new moodle_url('/course/pending.php'), get_string('coursespending'));
336 if (count($actions) === 0) {
339 return html_writer
::div(join(' | ', $actions), 'listing-actions category-listing-actions');
343 * Renderers the actions for individual category list items.
345 * @param coursecat $category
346 * @param array $actions
349 public function category_listitem_actions(coursecat
$category, array $actions = null) {
350 if ($actions === null) {
351 $actions = \core_course\management\helper
::get_category_listitem_actions($category);
353 $menu = new action_menu();
354 $menu->attributes
['class'] .= ' category-item-actions item-actions';
356 foreach ($actions as $key => $action) {
358 $menu->add(new action_menu_link(
362 in_array($key, array('show', 'hide', 'moveup', 'movedown')),
363 array('data-action' => $key, 'class' => 'action-'.$key)
369 return $this->render($menu);
373 * Renders bulk actions for categories.
375 * @param coursecat $category The currently selected category if there is one.
378 public function category_bulk_actions(coursecat
$category = null) {
381 if (!coursecat
::can_resort_any() && !coursecat
::can_change_parent_any()) {
384 $strgo = new lang_string('go');
386 $html = html_writer
::start_div('category-bulk-actions bulk-actions');
387 $html .= html_writer
::div(get_string('categorybulkaction'), 'accesshide', array('tabindex' => '0'));
388 if (coursecat
::can_resort_any()) {
389 $selectoptions = array(
390 'selectedcategories' => get_string('selectedcategories'),
391 'allcategories' => get_string('allcategories')
393 $form = html_writer
::start_div();
395 $selectoptions = array('thiscategory' => get_string('thiscategory')) +
$selectoptions;
396 $form .= html_writer
::empty_tag('input', array('type' => 'hidden', 'name' => 'currentcategoryid', 'value' => $category->id
));
398 $form .= html_writer
::div(
402 'selectedcategories',
404 array('aria-label' => get_string('selectcategorysort'))
407 $form .= html_writer
::div(
410 'name' => get_string('sortbyx', 'moodle', get_string('categoryname')),
411 'namedesc' => get_string('sortbyxreverse', 'moodle', get_string('categoryname')),
412 'idnumber' => get_string('sortbyx', 'moodle', get_string('idnumbercoursecategory')),
413 'idnumberdesc' => get_string('sortbyxreverse' , 'moodle' , get_string('idnumbercoursecategory')),
414 'none' => get_string('dontsortcategories')
416 'resortcategoriesby',
419 array('aria-label' => get_string('selectcategorysortby'))
422 $form .= html_writer
::div(
425 'fullname' => get_string('sortbyx', 'moodle', get_string('fullnamecourse')),
426 'fullnamedesc' => get_string('sortbyxreverse', 'moodle', get_string('fullnamecourse')),
427 'shortname' => get_string('sortbyx', 'moodle', get_string('shortnamecourse')),
428 'shortnamedesc' => get_string('sortbyxreverse', 'moodle', get_string('shortnamecourse')),
429 'idnumber' => get_string('sortbyx', 'moodle', get_string('idnumbercourse')),
430 'idnumberdesc' => get_string('sortbyxreverse', 'moodle', get_string('idnumbercourse')),
431 'timecreated' => get_string('sortbyx', 'moodle', get_string('timecreatedcourse')),
432 'timecreateddesc' => get_string('sortbyxreverse', 'moodle', get_string('timecreatedcourse')),
433 'none' => get_string('dontsortcourses')
438 array('aria-label' => get_string('selectcoursesortby'))
441 $form .= html_writer
::empty_tag('input', array('type' => 'submit', 'name' => 'bulksort', 'value' => get_string('sort')));
442 $form .= html_writer
::end_div();
444 $html .= html_writer
::start_div('detail-pair row yui3-g');
445 $html .= html_writer
::div(html_writer
::span(get_string('sorting')), 'pair-key span3 yui3-u-1-4');
446 $html .= html_writer
::div($form, 'pair-value span9 yui3-u-3-4');
447 $html .= html_writer
::end_div();
449 if (coursecat
::can_change_parent_any()) {
451 if (has_capability('moodle/category:manage', context_system
::instance())) {
452 $options[0] = coursecat
::get(0)->get_formatted_name();
454 $options +
= coursecat
::make_categories_list('moodle/category:manage');
455 $select = html_writer
::select(
459 array('' => 'choosedots'),
460 array('aria-labelledby' => 'moveselectedcategoriesto')
462 $submit = array('type' => 'submit', 'name' => 'bulkmovecategories', 'value' => get_string('move'));
463 $html .= $this->detail_pair(
464 html_writer
::span(get_string('moveselectedcategoriesto'), '', array('id' => 'moveselectedcategoriesto')),
465 $select . html_writer
::empty_tag('input', $submit)
468 $html .= html_writer
::end_div();
473 * Renders a course listing.
475 * @param coursecat $category The currently selected category. This is what the listing is focused on.
476 * @param course_in_list $course The currently selected course.
477 * @param int $page The page being displayed.
478 * @param int $perpage The number of courses to display per page.
481 public function course_listing(coursecat
$category = null, course_in_list
$course = null, $page = 0, $perpage = 20) {
483 if ($category === null) {
484 $html = html_writer
::start_div('select-a-category');
485 $html .= html_writer
::tag('h3', get_string('courses'),
486 array('id' => 'course-listing-title', 'tabindex' => '0'));
487 $html .= $this->output
->notification(get_string('selectacategory'), 'notifymessage');
488 $html .= html_writer
::end_div();
492 $page = max($page, 0);
493 $perpage = max($perpage, 2);
494 $totalcourses = $category->coursecount
;
495 $totalpages = ceil($totalcourses / $perpage);
496 if ($page > $totalpages - 1) {
497 $page = $totalpages - 1;
500 'offset' => $page * $perpage,
503 $courseid = isset($course) ?
$course->id
: null;
506 $class .= ' firstpage';
508 if ($page +
1 === (int)$totalpages) {
509 $class .= ' lastpage';
512 $html = html_writer
::start_div('course-listing'.$class, array(
513 'data-category' => $category->id
,
514 'data-page' => $page,
515 'data-totalpages' => $totalpages,
516 'data-totalcourses' => $totalcourses,
517 'data-canmoveoutof' => $category->can_move_courses_out_of() && $category->can_move_courses_into()
519 $html .= html_writer
::tag('h3', $category->get_formatted_name(),
520 array('id' => 'course-listing-title', 'tabindex' => '0'));
521 $html .= $this->course_listing_actions($category, $course, $perpage);
522 $html .= $this->listing_pagination($category, $page, $perpage);
523 $html .= html_writer
::start_tag('ul', array('class' => 'ml', 'role' => 'group'));
524 foreach ($category->get_courses($options) as $listitem) {
525 $html .= $this->course_listitem($category, $listitem, $courseid);
527 $html .= html_writer
::end_tag('ul');
528 $html .= $this->listing_pagination($category, $page, $perpage, true);
529 $html .= $this->course_bulk_actions($category);
530 $html .= html_writer
::end_div();
535 * Renders pagination for a course listing.
537 * @param coursecat $category The category to produce pagination for.
538 * @param int $page The current page.
539 * @param int $perpage The number of courses to display per page.
540 * @param bool $showtotals Set to true to show the total number of courses and what is being displayed.
543 protected function listing_pagination(coursecat
$category, $page, $perpage, $showtotals = false) {
545 $totalcourses = $category->get_courses_count();
546 $totalpages = ceil($totalcourses / $perpage);
548 if ($totalpages == 0) {
549 $str = get_string('nocoursesyet');
550 } else if ($totalpages == 1) {
551 $str = get_string('showingacourses', 'moodle', $totalcourses);
554 $a->start
= ($page * $perpage) +
1;
555 $a->end
= min((($page +
1) * $perpage), $totalcourses);
556 $a->total
= $totalcourses;
557 $str = get_string('showingxofycourses', 'moodle', $a);
559 $html .= html_writer
::div($str, 'listing-pagination-totals dimmed');
562 if ($totalcourses <= $perpage) {
566 $span = $aside * 2 +
1;
567 $start = max($page - $aside, 0);
568 $end = min($page +
$aside, $totalpages - 1);
569 if (($end - $start) < $span) {
571 $end = min($totalpages - 1, $span - 1);
572 } else if ($end == ($totalpages - 1)) {
573 $start = max(0, $end - $span +
1);
577 $baseurl = new moodle_url('/course/management.php', array('categoryid' => $category->id
));
579 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => 0)), get_string('first'));
580 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $page - 1)), get_string('prev'));
583 for ($i = $start; $i <= $end; $i++
) {
586 $class = 'active-page';
588 $pageurl = new moodle_url($baseurl, array('page' => $i));
589 $items[] = $this->action_button($pageurl, $i +
1, null, $class, get_string('pagea', 'moodle', $i+
1));
591 if ($page < ($totalpages - 1)) {
593 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $page +
1)), get_string('next'));
594 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $totalpages - 1)), get_string('last'));
597 $html .= html_writer
::div(join('', $items), 'listing-pagination');
602 * Renderers a course list item.
604 * This function will be called for every course being displayed by course_listing.
606 * @param coursecat $category The currently selected category and the category the course belongs to.
607 * @param course_in_list $course The course to produce HTML for.
608 * @param int $selectedcourse The id of the currently selected course.
611 public function course_listitem(coursecat
$category, course_in_list
$course, $selectedcourse) {
613 $text = $course->get_formatted_name();
615 'class' => 'listitem listitem-course',
616 'data-id' => $course->id
,
617 'data-selected' => ($selectedcourse == $course->id
) ?
'1' : '0',
618 'data-visible' => $course->visible ?
'1' : '0'
621 $bulkcourseinput = array(
622 'type' => 'checkbox',
624 'value' => $course->id
,
625 'class' => 'bulk-action-checkbox',
626 'aria-label' => get_string('bulkactionselect', 'moodle', $text),
627 'data-action' => 'select'
629 if (!$category->has_manage_capability()) {
630 // Very very hardcoded here.
631 $bulkcourseinput['style'] = 'visibility:hidden';
634 $viewcourseurl = new moodle_url($this->page
->url
, array('courseid' => $course->id
));
636 $html = html_writer
::start_tag('li', $attributes);
637 $html .= html_writer
::start_div('clearfix');
639 if ($category->can_resort_courses()) {
640 // In order for dnd to be available the user must be able to resort the category children..
641 $html .= html_writer
::div($this->output
->pix_icon('i/move_2d', get_string('dndcourse')), 'float-left drag-handle');
644 $html .= html_writer
::start_div('ba-checkbox float-left');
645 $html .= html_writer
::empty_tag('input', $bulkcourseinput).' ';
646 $html .= html_writer
::end_div();
647 $html .= html_writer
::link($viewcourseurl, $text, array('class' => 'float-left coursename'));
648 $html .= html_writer
::start_div('float-right');
649 if ($course->idnumber
) {
650 $html .= html_writer
::tag('span', s($course->idnumber
), array('class' => 'dimmed idnumber'));
652 $html .= $this->course_listitem_actions($category, $course);
653 $html .= html_writer
::end_div();
654 $html .= html_writer
::end_div();
655 $html .= html_writer
::end_tag('li');
660 * Renderers actions for the course listing.
662 * Not to be confused with course_listitem_actions which renderers the actions for individual courses.
664 * @param coursecat $category
665 * @param course_in_list $course The currently selected course.
666 * @param int $perpage
669 public function course_listing_actions(coursecat
$category, course_in_list
$course = null, $perpage = 20) {
671 if ($category->can_create_course()) {
672 $url = new moodle_url('/course/edit.php', array('category' => $category->id
, 'returnto' => 'catmanage'));
673 $actions[] = html_writer
::link($url, get_string('createnewcourse'));
675 if ($category->can_request_course()) {
676 // Request a new course.
677 $url = new moodle_url('/course/request.php', array('return' => 'management'));
678 $actions[] = html_writer
::link($url, get_string('requestcourse'));
680 if ($category->can_resort_courses()) {
681 $params = $this->page
->url
->params();
682 $params['action'] = 'resortcourses';
683 $params['sesskey'] = sesskey();
684 $baseurl = new moodle_url('/course/management.php', $params);
685 $fullnameurl = new moodle_url($baseurl, array('resort' => 'fullname'));
686 $fullnameurldesc = new moodle_url($baseurl, array('resort' => 'fullnamedesc'));
687 $shortnameurl = new moodle_url($baseurl, array('resort' => 'shortname'));
688 $shortnameurldesc = new moodle_url($baseurl, array('resort' => 'shortnamedesc'));
689 $idnumberurl = new moodle_url($baseurl, array('resort' => 'idnumber'));
690 $idnumberdescurl = new moodle_url($baseurl, array('resort' => 'idnumberdesc'));
691 $timecreatedurl = new moodle_url($baseurl, array('resort' => 'timecreated'));
692 $timecreateddescurl = new moodle_url($baseurl, array('resort' => 'timecreateddesc'));
693 $menu = new action_menu(array(
694 new action_menu_link_secondary($fullnameurl,
696 get_string('sortbyx', 'moodle', get_string('fullnamecourse'))),
697 new action_menu_link_secondary($fullnameurldesc,
699 get_string('sortbyxreverse', 'moodle', get_string('fullnamecourse'))),
700 new action_menu_link_secondary($shortnameurl,
702 get_string('sortbyx', 'moodle', get_string('shortnamecourse'))),
703 new action_menu_link_secondary($shortnameurldesc,
705 get_string('sortbyxreverse', 'moodle', get_string('shortnamecourse'))),
706 new action_menu_link_secondary($idnumberurl,
708 get_string('sortbyx', 'moodle', get_string('idnumbercourse'))),
709 new action_menu_link_secondary($idnumberdescurl,
711 get_string('sortbyxreverse', 'moodle', get_string('idnumbercourse'))),
712 new action_menu_link_secondary($timecreatedurl,
714 get_string('sortbyx', 'moodle', get_string('timecreatedcourse'))),
715 new action_menu_link_secondary($timecreateddescurl,
717 get_string('sortbyxreverse', 'moodle', get_string('timecreatedcourse')))
719 $menu->set_menu_trigger(get_string('resortcourses'));
720 $actions[] = $this->render($menu);
722 $strall = get_string('all');
723 $menu = new action_menu(array(
724 new action_menu_link_secondary(new moodle_url($this->page
->url
, array('perpage' => 5)), null, 5),
725 new action_menu_link_secondary(new moodle_url($this->page
->url
, array('perpage' => 10)), null, 10),
726 new action_menu_link_secondary(new moodle_url($this->page
->url
, array('perpage' => 20)), null, 20),
727 new action_menu_link_secondary(new moodle_url($this->page
->url
, array('perpage' => 50)), null, 50),
728 new action_menu_link_secondary(new moodle_url($this->page
->url
, array('perpage' => 100)), null, 100),
729 new action_menu_link_secondary(new moodle_url($this->page
->url
, array('perpage' => 999)), null, $strall),
731 if ((int)$perpage === 999) {
734 $menu->attributes
['class'] .= ' courses-per-page';
735 $menu->set_menu_trigger(get_string('perpagea', 'moodle', $perpage));
736 $actions[] = $this->render($menu);
737 return html_writer
::div(join(' | ', $actions), 'listing-actions course-listing-actions');
741 * Renderers actions for individual course actions.
743 * @param coursecat $category The currently selected category.
744 * @param course_in_list $course The course to renderer actions for.
747 public function course_listitem_actions(coursecat
$category, course_in_list
$course) {
748 $actions = \core_course\management\helper
::get_course_listitem_actions($category, $course);
749 if (empty($actions)) {
752 $actionshtml = array();
753 foreach ($actions as $action) {
754 $action['attributes']['role'] = 'button';
755 $actionshtml[] = $this->output
->action_icon($action['url'], $action['icon'], null, $action['attributes']);
757 return html_writer
::span(join('', $actionshtml), 'course-item-actions item-actions');
761 * Renderers bulk actions that can be performed on courses.
763 * @param coursecat $category The currently selected category and the category in which courses that
764 * are selectable belong.
767 public function course_bulk_actions(coursecat
$category) {
768 $html = html_writer
::start_div('course-bulk-actions bulk-actions');
769 if ($category->can_move_courses_out_of()) {
770 $html .= html_writer
::div(get_string('coursebulkaction'), 'accesshide', array('tabindex' => '0'));
771 $options = coursecat
::make_categories_list('moodle/category:manage');
772 $select = html_writer
::select(
776 array('' => 'choosedots'),
777 array('aria-labelledby' => 'moveselectedcoursesto')
779 $submit = array('type' => 'submit', 'name' => 'bulkmovecourses', 'value' => get_string('move'));
780 $html .= $this->detail_pair(
781 html_writer
::span(get_string('moveselectedcoursesto'), '', array('id' => 'moveselectedcoursesto')),
782 $select . html_writer
::empty_tag('input', $submit)
785 $html .= html_writer
::end_div();
790 * Renderers bulk actions that can be performed on courses in search returns
794 public function course_search_bulk_actions() {
795 $html = html_writer
::start_div('course-bulk-actions bulk-actions');
796 $html .= html_writer
::div(get_string('coursebulkaction'), 'accesshide', array('tabindex' => '0'));
797 $options = coursecat
::make_categories_list('moodle/category:manage');
798 $select = html_writer
::select(
802 array('' => 'choosedots'),
803 array('aria-labelledby' => 'moveselectedcoursesto')
805 $submit = array('type' => 'submit', 'name' => 'bulkmovecourses', 'value' => get_string('move'));
806 $html .= $this->detail_pair(
807 html_writer
::span(get_string('moveselectedcoursesto'), '', array('id' => 'moveselectedcoursesto')),
808 $select . html_writer
::empty_tag('input', $submit)
810 $html .= html_writer
::end_div();
815 * Renderers detailed course information.
817 * @param course_in_list $course The course to display details for.
820 public function course_detail(course_in_list
$course) {
821 $details = \core_course\management\helper
::get_course_detail_array($course);
822 $fullname = $details['fullname']['value'];
824 $html = html_writer
::start_div('course-detail');
825 $html .= html_writer
::tag('h3', $fullname, array('id' => 'course-detail-title', 'tabindex' => '0'));
826 $html .= $this->course_detail_actions($course);
827 foreach ($details as $class => $data) {
828 $html .= $this->detail_pair($data['key'], $data['value'], $class);
830 $html .= html_writer
::end_div();
835 * Renderers a key value pair of information for display.
838 * @param string $value
839 * @param string $class
842 protected function detail_pair($key, $value, $class ='') {
843 $html = html_writer
::start_div('detail-pair row yui3-g '.preg_replace('#[^a-zA-Z0-9_\-]#', '-', $class));
844 $html .= html_writer
::div(html_writer
::span($key), 'pair-key span3 yui3-u-1-4');
845 $html .= html_writer
::div(html_writer
::span($value), 'pair-value span9 yui3-u-3-4');
846 $html .= html_writer
::end_div();
851 * A collection of actions for a course.
853 * @param course_in_list $course The course to display actions for.
856 public function course_detail_actions(course_in_list
$course) {
857 $actions = \core_course\management\helper
::get_course_detail_actions($course);
858 if (empty($actions)) {
862 foreach ($actions as $action) {
863 $options[] = $this->action_link($action['url'], $action['string']);
865 return html_writer
::div(join(' | ', $options), 'listing-actions course-detail-listing-actions');
869 * Creates an action button (styled link)
871 * @param moodle_url $url The URL to go to when clicked.
872 * @param string $text The text for the button.
873 * @param string $id An id to give the button.
874 * @param string $class A class to give the button.
875 * @param array $attributes Any additional attributes
878 protected function action_button(moodle_url
$url, $text, $id = null, $class = null, $title = null, array $attributes = array()) {
879 if (isset($attributes['class'])) {
880 $attributes['class'] .= ' yui3-button';
882 $attributes['class'] = 'yui3-button';
885 $attributes['id'] = $id;
887 if (!is_null($class)) {
888 $attributes['class'] .= ' '.$class;
890 if (is_null($title)) {
893 $attributes['title'] = $title;
894 if (!isset($attributes['role'])) {
895 $attributes['role'] = 'button';
897 return html_writer
::link($url, $text, $attributes);
903 * Call {@link core_course_management_renderer::grid_column_start()} to create columns.
905 * @param string $id An id to give this grid.
906 * @param string $class A class to give this grid.
909 public function grid_start($id = null, $class = null) {
910 $gridclass = 'grid-row-r row-fluid';
911 if (is_null($class)) {
914 $class .= ' ' . $gridclass;
916 $attributes = array();
918 $attributes['id'] = $id;
920 return html_writer
::start_div($class, $attributes);
928 public function grid_end() {
929 return html_writer
::end_div();
933 * Opens a grid column
935 * @param int $size The number of segments this column should span.
936 * @param string $id An id to give the column.
937 * @param string $class A class to give the column.
940 public function grid_column_start($size, $id = null, $class = null) {
942 // Calculate Bootstrap grid sizing.
943 $bootstrapclass = 'span'.$size;
945 // Calculate YUI grid sizing.
951 $divisors = array(8, 6, 5, 4, 3, 2);
952 foreach ($divisors as $divisor) {
953 if (($maxsize %
$divisor === 0) && ($size %
$divisor === 0)) {
954 $maxsize = $maxsize / $divisor;
955 $size = $size / $divisor;
961 $yuigridclass = "grid-col-{$size}-{$maxsize} grid-col";
963 $yuigridclass = "grid-col-1 grid-col";
966 if (is_null($class)) {
967 $class = $yuigridclass . ' ' . $bootstrapclass;
969 $class .= ' ' . $yuigridclass . ' ' . $bootstrapclass;
971 $attributes = array();
973 $attributes['id'] = $id;
975 return html_writer
::start_div($class, $attributes);
979 * Closes a grid column.
983 public function grid_column_end() {
984 return html_writer
::end_div();
988 * Renders an action_icon.
990 * This function uses the {@link core_renderer::action_link()} method for the
991 * most part. What it does different is prepare the icon as HTML and use it
994 * @param string|moodle_url $url A string URL or moodel_url
995 * @param pix_icon $pixicon
996 * @param component_action $action
997 * @param array $attributes associative array of html link attributes + disabled
998 * @param bool $linktext show title next to image in link
999 * @return string HTML fragment
1001 public function action_icon($url, pix_icon
$pixicon, component_action
$action = null,
1002 array $attributes = null, $linktext = false) {
1003 if (!($url instanceof moodle_url
)) {
1004 $url = new moodle_url($url);
1006 $attributes = (array)$attributes;
1008 if (empty($attributes['class'])) {
1009 // Let devs override the class via $attributes.
1010 $attributes['class'] = 'action-icon';
1013 $icon = $this->render($pixicon);
1016 $text = $pixicon->attributes
['alt'];
1021 return $this->action_link($url, $icon.$text, $action, $attributes);
1025 * Displays a view mode selector.
1027 * @param array $modes An array of view modes.
1028 * @param string $currentmode The current view mode.
1029 * @param moodle_url $url The URL to use when changing actions. Defaults to the page URL.
1030 * @param string $param The param name.
1033 public function view_mode_selector(array $modes, $currentmode, moodle_url
$url = null, $param = 'view') {
1034 if ($url === null) {
1035 $url = $this->page
->url
;
1038 $menu = new action_menu
;
1039 $menu->attributes
['class'] .= ' view-mode-selector vms';
1042 foreach ($modes as $mode => $modestr) {
1043 $attributes = array(
1044 'class' => 'vms-mode',
1045 'data-mode' => $mode
1047 if ($currentmode === $mode) {
1048 $attributes['class'] .= ' currentmode';
1049 $selected = $modestr;
1051 if ($selected === null) {
1052 $selected = $modestr;
1054 $modeurl = new moodle_url($url, array($param => $mode));
1055 if ($mode === 'default') {
1056 $modeurl->remove_params($param);
1058 $menu->add(new action_menu_link_secondary($modeurl, null, $modestr, $attributes));
1061 $menu->set_menu_trigger($selected);
1063 $html = html_writer
::start_div('view-mode-selector vms');
1064 $html .= get_string('viewing').' '.$this->render($menu);
1065 $html .= html_writer
::end_div();
1071 * Displays a search result listing.
1073 * @param array $courses The courses to display.
1074 * @param int $totalcourses The total number of courses to display.
1075 * @param course_in_list $course The currently selected course if there is one.
1076 * @param int $page The current page, starting at 0.
1077 * @param int $perpage The number of courses to display per page.
1078 * @param string $search The string we are searching for.
1081 public function search_listing(array $courses, $totalcourses, course_in_list
$course = null, $page = 0, $perpage = 20,
1083 $page = max($page, 0);
1084 $perpage = max($perpage, 2);
1085 $totalpages = ceil($totalcourses / $perpage);
1086 if ($page > $totalpages - 1) {
1087 $page = $totalpages - 1;
1089 $courseid = isset($course) ?
$course->id
: null;
1092 $i = $page * $perpage;
1094 $html = html_writer
::start_div('course-listing', array(
1095 'data-category' => 'search',
1096 'data-page' => $page,
1097 'data-totalpages' => $totalpages,
1098 'data-totalcourses' => $totalcourses
1100 $html .= html_writer
::tag('h3', get_string('courses'));
1101 $html .= $this->search_pagination($totalcourses, $page, $perpage);
1102 $html .= html_writer
::start_tag('ul', array('class' => 'ml'));
1103 foreach ($courses as $listitem) {
1105 if ($i == $totalcourses) {
1108 $html .= $this->search_listitem($listitem, $courseid, $first, $last);
1111 $html .= html_writer
::end_tag('ul');
1112 $html .= $this->search_pagination($totalcourses, $page, $perpage, true, $search);
1113 $html .= $this->course_search_bulk_actions();
1114 $html .= html_writer
::end_div();
1119 * Displays pagination for search results.
1121 * @param int $totalcourses The total number of courses to be displayed.
1122 * @param int $page The current page.
1123 * @param int $perpage The number of courses being displayed.
1124 * @param bool $showtotals Whether or not to print total information.
1125 * @param string $search The string we are searching for.
1128 protected function search_pagination($totalcourses, $page, $perpage, $showtotals = false, $search = '') {
1130 $totalpages = ceil($totalcourses / $perpage);
1132 if ($totalpages == 0) {
1133 $str = get_string('nocoursesfound', 'moodle', $search);
1134 } else if ($totalpages == 1) {
1135 $str = get_string('showingacourses', 'moodle', $totalcourses);
1138 $a->start
= ($page * $perpage) +
1;
1139 $a->end
= min((($page +
1) * $perpage), $totalcourses);
1140 $a->total
= $totalcourses;
1141 $str = get_string('showingxofycourses', 'moodle', $a);
1143 $html .= html_writer
::div($str, 'listing-pagination-totals dimmed');
1146 if ($totalcourses < $perpage) {
1150 $span = $aside * 2 +
1;
1151 $start = max($page - $aside, 0);
1152 $end = min($page +
$aside, $totalpages - 1);
1153 if (($end - $start) < $span) {
1155 $end = min($totalpages - 1, $span - 1);
1156 } else if ($end == ($totalpages - 1)) {
1157 $start = max(0, $end - $span +
1);
1161 $baseurl = $this->page
->url
;
1163 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => 0)), get_string('first'));
1164 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $page - 1)), get_string('prev'));
1167 for ($i = $start; $i <= $end; $i++
) {
1170 $class = 'active-page';
1172 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $i)), $i +
1, null, $class);
1174 if ($page < ($totalpages - 1)) {
1176 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $page +
1)), get_string('next'));
1177 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $totalpages - 1)), get_string('last'));
1180 $html .= html_writer
::div(join('', $items), 'listing-pagination');
1185 * Renderers a search result course list item.
1187 * This function will be called for every course being displayed by course_listing.
1189 * @param course_in_list $course The course to produce HTML for.
1190 * @param int $selectedcourse The id of the currently selected course.
1193 public function search_listitem(course_in_list
$course, $selectedcourse) {
1195 $text = $course->get_formatted_name();
1196 $attributes = array(
1197 'class' => 'listitem listitem-course',
1198 'data-id' => $course->id
,
1199 'data-selected' => ($selectedcourse == $course->id
) ?
'1' : '0',
1200 'data-visible' => $course->visible ?
'1' : '0'
1202 $bulkcourseinput = '';
1203 if (coursecat
::get($course->category
)->can_move_courses_out_of()) {
1204 $bulkcourseinput = array(
1205 'type' => 'checkbox',
1207 'value' => $course->id
,
1208 'class' => 'bulk-action-checkbox',
1209 'aria-label' => get_string('bulkactionselect', 'moodle', $text),
1210 'data-action' => 'select'
1213 $viewcourseurl = new moodle_url($this->page
->url
, array('courseid' => $course->id
));
1214 $categoryname = coursecat
::get($course->category
)->get_formatted_name();
1216 $html = html_writer
::start_tag('li', $attributes);
1217 $html .= html_writer
::start_div('clearfix');
1218 $html .= html_writer
::start_div('float-left');
1219 if ($bulkcourseinput) {
1220 $html .= html_writer
::empty_tag('input', $bulkcourseinput).' ';
1222 $html .= html_writer
::end_div();
1223 $html .= html_writer
::link($viewcourseurl, $text, array('class' => 'float-left coursename'));
1224 $html .= html_writer
::tag('span', $categoryname, array('class' => 'float-left categoryname'));
1225 $html .= html_writer
::start_div('float-right');
1226 $html .= $this->search_listitem_actions($course);
1227 $html .= html_writer
::tag('span', s($course->idnumber
), array('class' => 'dimmed idnumber'));
1228 $html .= html_writer
::end_div();
1229 $html .= html_writer
::end_div();
1230 $html .= html_writer
::end_tag('li');
1235 * Renderers actions for individual course actions.
1237 * @param course_in_list $course The course to renderer actions for.
1240 public function search_listitem_actions(course_in_list
$course) {
1241 $baseurl = new moodle_url(
1242 '/course/managementsearch.php',
1243 array('courseid' => $course->id
, 'categoryid' => $course->category
, 'sesskey' => sesskey())
1247 if ($course->can_access()) {
1248 if ($course->can_edit()) {
1249 $actions[] = $this->output
->action_icon(
1250 new moodle_url('/course/edit.php', array('id' => $course->id
)),
1251 new pix_icon('t/edit', get_string('edit')),
1253 array('class' => 'action-edit')
1257 if ($course->can_delete()) {
1258 $actions[] = $this->output
->action_icon(
1259 new moodle_url('/course/delete.php', array('id' => $course->id
)),
1260 new pix_icon('t/delete', get_string('delete')),
1262 array('class' => 'action-delete')
1266 if ($course->can_change_visibility()) {
1267 $actions[] = $this->output
->action_icon(
1268 new moodle_url($baseurl, array('action' => 'hidecourse')),
1269 new pix_icon('t/hide', get_string('hide')),
1271 array('data-action' => 'hide', 'class' => 'action-hide')
1273 $actions[] = $this->output
->action_icon(
1274 new moodle_url($baseurl, array('action' => 'showcourse')),
1275 new pix_icon('t/show', get_string('show')),
1277 array('data-action' => 'show', 'class' => 'action-show')
1281 if (empty($actions)) {
1284 return html_writer
::span(join('', $actions), 'course-item-actions item-actions');
1288 * Renders html to display a course search form
1290 * @param string $value default value to populate the search field
1291 * @param string $format display format - 'plain' (default), 'short' or 'navbar'
1294 public function course_search_form($value = '', $format = 'plain') {
1296 $formid = 'coursesearch';
1297 if ((++
$count) > 1) {
1303 $formid = 'coursesearchnavbar';
1304 $inputid = 'navsearchbox';
1308 $inputid = 'shortsearchbox';
1312 $inputid = 'coursesearchbox';
1316 $strsearchcourses = get_string("searchcourses");
1317 $searchurl = new moodle_url('/course/management.php');
1319 $output = html_writer
::start_tag('form', array('id' => $formid, 'action' => $searchurl, 'method' => 'get'));
1320 $output .= html_writer
::start_tag('fieldset', array('class' => 'coursesearchbox invisiblefieldset'));
1321 $output .= html_writer
::tag('label', $strsearchcourses.': ', array('for' => $inputid));
1322 $output .= html_writer
::empty_tag('input', array('type' => 'text', 'id' => $inputid,
1323 'size' => $inputsize, 'name' => 'search', 'value' => s($value)));
1324 $output .= html_writer
::empty_tag('input', array('type' => 'submit',
1325 'value' => get_string('go')));
1326 $output .= html_writer
::end_tag('fieldset');
1327 $output .= html_writer
::end_tag('form');
1333 * Creates access hidden skip to links for the displayed sections.
1335 * @param bool $displaycategorylisting
1336 * @param bool $displaycourselisting
1337 * @param bool $displaycoursedetail
1340 public function accessible_skipto_links($displaycategorylisting, $displaycourselisting, $displaycoursedetail) {
1341 $html = html_writer
::start_div('skiplinks accesshide');
1342 $url = new moodle_url($this->page
->url
);
1343 if ($displaycategorylisting) {
1344 $url->set_anchor('category-listing');
1345 $html .= html_writer
::link($url, get_string('skiptocategorylisting'), array('class' => 'skip'));
1347 if ($displaycourselisting) {
1348 $url->set_anchor('course-listing');
1349 $html .= html_writer
::link($url, get_string('skiptocourselisting'), array('class' => 'skip'));
1351 if ($displaycoursedetail) {
1352 $url->set_anchor('course-detail');
1353 $html .= html_writer
::link($url, get_string('skiptocoursedetails'), array('class' => 'skip'));
1355 $html .= html_writer
::end_div();