weekly release 2.8dev
[moodle.git] / course / classes / management_renderer.php
CommitLineData
5dc361e1
SH
1<?php
2// This file is part of Moodle - http://moodle.org/
3//
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.
8//
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.
13//
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/>.
16
17/**
18 * Contains renderers for the course management pages.
19 *
20 * @package core_course
21 * @copyright 2013 Sam Hemelryk
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25defined('MOODLE_INTERNAL') || die;
26
27require_once($CFG->dirroot.'/course/renderer.php');
28
29/**
30 * Main renderer for the course management pages.
31 *
32 * @package core_course
33 * @copyright 2013 Sam Hemelryk
34 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
35 */
36class core_course_management_renderer extends plugin_renderer_base {
37
38 /**
39 * Initialises the JS required to enhance the management interface.
40 *
41 * Thunderbirds are go, this function kicks into gear the JS that makes the
42 * course management pages that much cooler.
43 */
44 public function enhance_management_interface() {
484c4c6c 45 $this->page->requires->yui_module('moodle-course-management', 'M.course.management.init');
5dc361e1 46 $this->page->requires->strings_for_js(
d0647301
SH
47 array(
48 'show',
49 'showcategory',
50 'hide',
51 'expand',
52 'expandcategory',
53 'collapse',
54 'collapsecategory',
55 'confirmcoursemove',
56 'move',
57 'cancel',
58 'confirm'
59 ),
5dc361e1
SH
60 'moodle'
61 );
62 }
63
64 /**
65 * Displays a heading for the management pages.
66 *
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.
70 * @return string
71 */
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);
76 }
77 if ($viewmode !== null) {
d0647301
SH
78 $html .= html_writer::start_div();
79 $html .= $this->view_mode_selector(\core_course\management\helper::get_management_viewmodes(), $viewmode);
5dc361e1 80 if ($viewmode === 'courses') {
484c4c6c 81 $categories = coursecat::make_categories_list(array('moodle/category:manage', 'moodle/course:create'));
5dc361e1
SH
82 $nothing = false;
83 if ($categoryid === null) {
84 $nothing = array('' => get_string('selectacategory'));
85 $categoryid = '';
86 }
87 $select = new single_select($this->page->url, 'categoryid', $categories, $categoryid, $nothing);
88 $html .= $this->render($select);
89 }
d0647301 90 $html .= html_writer::end_div();
5dc361e1
SH
91 }
92 $html .= html_writer::end_div();
93 return $html;
94 }
95
96 /**
97 * Prepares the form element for the course category listing bulk actions.
98 *
99 * @return string
100 */
101 public function management_form_start() {
102 $form = array('action' => $this->page->url->out(), 'method' => 'POST', 'id' => 'coursecat-management');
103
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'));
107 return $html;
108 }
109
110 /**
111 * Closes the course category bulk management form.
112 *
113 * @return string
114 */
115 public function management_form_end() {
116 return html_writer::end_tag('form');
117 }
118
119 /**
120 * Presents a course category listing.
121 *
122 * @param coursecat $category The currently selected category. Also the category to highlight in the listing.
123 * @return string
124 */
125 public function category_listing(coursecat $category = null) {
126
127 if ($category === null) {
5dc361e1 128 $selectedparents = array();
f454e324 129 $selectedcategory = null;
5dc361e1
SH
130 } else {
131 $selectedparents = $category->get_parents();
132 $selectedparents[] = $category->id;
f454e324 133 $selectedcategory = $category->id;
5dc361e1 134 }
d5de8747
SH
135 $catatlevel = \core_course\management\helper::get_expanded_categories('');
136 $catatlevel[] = array_shift($selectedparents);
137 $catatlevel = array_unique($catatlevel);
5dc361e1 138
67e1f268 139 $listing = coursecat::get(0)->get_children();
5dc361e1 140
7fd307b1
SH
141 $attributes = array(
142 'class' => 'ml',
143 'role' => 'tree',
144 'aria-labelledby' => 'category-listing-title'
145 );
146
5dc361e1 147 $html = html_writer::start_div('category-listing');
7fd307b1 148 $html .= html_writer::tag('h3', get_string('categories'), array('id' => 'category-listing-title'));
b488058f 149 $html .= $this->category_listing_actions($category);
7fd307b1 150 $html .= html_writer::start_tag('ul', $attributes);
5dc361e1
SH
151 foreach ($listing as $listitem) {
152 // Render each category in the listing.
153 $subcategories = array();
d5de8747 154 if (in_array($listitem->id, $catatlevel)) {
5dc361e1
SH
155 $subcategories = $listitem->get_children();
156 }
157 $html .= $this->category_listitem(
158 $listitem,
159 $subcategories,
160 $listitem->get_children_count(),
f454e324 161 $selectedcategory,
5dc361e1
SH
162 $selectedparents
163 );
164 }
165 $html .= html_writer::end_tag('ul');
c7a2291f 166 $html .= $this->category_bulk_actions($category);
5dc361e1
SH
167 $html .= html_writer::end_div();
168 return $html;
169 }
170
171 /**
172 * Renders a category list item.
173 *
174 * This function gets called recursively to render sub categories.
175 *
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.
181 * @return string
182 */
183 public function category_listitem(coursecat $category, array $subcategories, $totalsubcategories,
184 $selectedcategory = null, $selectedcategories = array()) {
d5de8747 185
5dc361e1
SH
186 $isexpandable = ($totalsubcategories > 0);
187 $isexpanded = (!empty($subcategories));
f454e324 188 $activecategory = ($selectedcategory === $category->id);
5dc361e1
SH
189 $attributes = array(
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',
7fd307b1
SH
195 'data-visible' => $category->visible ? '1' : '0',
196 'role' => 'treeitem',
197 'aria-expanded' => $isexpanded ? 'true' : 'false'
5dc361e1
SH
198 );
199 $text = $category->get_formatted_name();
d0647301
SH
200 if ($category->parent) {
201 $a = new stdClass;
202 $a->category = $text;
203 $a->parentcategory = $category->get_parent_coursecat()->get_formatted_name();
204 $textlabel = get_string('categorysubcategoryof', 'moodle', $a);
205 }
5dc361e1 206 $courseicon = $this->output->pix_icon('i/course', get_string('courses'));
cd96b7d3
SH
207 $bcatinput = array(
208 'type' => 'checkbox',
209 'name' => 'bcat[]',
210 'value' => $category->id,
211 'class' => 'bulk-action-checkbox',
a5888fb5
RT
212 'aria-label' => get_string('bulkactionselect', 'moodle', $text),
213 'data-action' => 'select'
cd96b7d3 214 );
b488058f
SH
215
216 if (!$category->can_resort_subcategories() && !$category->has_manage_capability()) {
217 // Very very hardcoded here.
218 $bcatinput['style'] = 'visibility:hidden';
219 }
220
5dc361e1
SH
221 $viewcaturl = new moodle_url('/course/management.php', array('categoryid' => $category->id));
222 if ($isexpanded) {
d0647301
SH
223 $icon = $this->output->pix_icon('t/switch_minus', get_string('collapse'), 'moodle', array('class' => 'tree-icon', 'title' => ''));
224 $icon = html_writer::link(
225 $viewcaturl,
226 $icon,
227 array(
228 'class' => 'float-left',
229 'data-action' => 'collapse',
230 'title' => get_string('collapsecategory', 'moodle', $text),
231 'aria-controls' => 'subcategoryof'.$category->id
232 )
233 );
5dc361e1 234 } else if ($isexpandable) {
d0647301
SH
235 $icon = $this->output->pix_icon('t/switch_plus', get_string('expand'), 'moodle', array('class' => 'tree-icon', 'title' => ''));
236 $icon = html_writer::link(
237 $viewcaturl,
238 $icon,
239 array(
240 'class' => 'float-left',
241 'data-action' => 'expand',
242 'title' => get_string('expandcategory', 'moodle', $text)
243 )
244 );
5dc361e1 245 } else {
d0647301
SH
246 $icon = $this->output->pix_icon(
247 'i/navigationitem',
248 '',
249 'moodle',
250 array('class' => 'tree-icon', 'title' => get_string('showcategory', 'moodle', $text))
251 );
252 $icon = html_writer::span($icon, 'float-left');
5dc361e1 253 }
b488058f 254 $actions = \core_course\management\helper::get_category_listitem_actions($category);
484c4c6c 255 $hasactions = !empty($actions) || $category->can_create_course();
5dc361e1
SH
256
257 $html = html_writer::start_tag('li', $attributes);
258 $html .= html_writer::start_div('clearfix');
3b681e6c 259 $html .= html_writer::start_div('float-left ba-checkbox');
5dc361e1
SH
260 $html .= html_writer::empty_tag('input', $bcatinput).'&nbsp;';
261 $html .= html_writer::end_div();
262 $html .= $icon;
b488058f 263 if ($hasactions) {
d0647301 264 $textattributes = array('class' => 'float-left categoryname');
b488058f 265 } else {
d0647301
SH
266 $textattributes = array('class' => 'float-left categoryname without-actions');
267 }
268 if (isset($textlabel)) {
269 $textattributes['aria-label'] = $textlabel;
b488058f 270 }
d0647301 271 $html .= html_writer::link($viewcaturl, $text, $textattributes);
5dc361e1 272 $html .= html_writer::start_div('float-right');
c7a2291f
SH
273 if ($category->idnumber) {
274 $html .= html_writer::tag('span', s($category->idnumber), array('class' => 'dimmed idnumber'));
275 }
b488058f
SH
276 if ($hasactions) {
277 $html .= $this->category_listitem_actions($category, $actions);
278 }
7fd307b1 279 $countid = 'course-count-'.$category->id;
38a15200 280 $html .= html_writer::span(
d0647301
SH
281 html_writer::span($category->get_courses_count()) .
282 html_writer::span(get_string('courses'), 'accesshide', array('id' => $countid)) .
283 $courseicon,
38a15200
SH
284 'course-count dimmed',
285 array('aria-labelledby' => $countid)
286 );
5dc361e1
SH
287 $html .= html_writer::end_div();
288 $html .= html_writer::end_div();
289 if ($isexpanded) {
d0647301
SH
290 $html .= html_writer::start_tag('ul',
291 array('class' => 'ml', 'role' => 'group', 'id' => 'subcategoryof'.$category->id));
d5de8747
SH
292 $catatlevel = \core_course\management\helper::get_expanded_categories($category->path);
293 $catatlevel[] = array_shift($selectedcategories);
294 $catatlevel = array_unique($catatlevel);
5dc361e1 295 foreach ($subcategories as $listitem) {
d5de8747 296 $childcategories = (in_array($listitem->id, $catatlevel)) ? $listitem->get_children() : array();
5dc361e1
SH
297 $html .= $this->category_listitem(
298 $listitem,
299 $childcategories,
300 $listitem->get_children_count(),
301 $selectedcategory,
302 $selectedcategories
303 );
304 }
305 $html .= html_writer::end_tag('ul');
306 }
307 $html .= html_writer::end_tag('li');
308 return $html;
309 }
310
311 /**
312 * Renderers the actions that are possible for the course category listing.
313 *
314 * These are not the actions associated with an individual category listing.
315 * That happens through category_listitem_actions.
316 *
317 * @param coursecat $category
318 * @return string
319 */
b488058f 320 public function category_listing_actions(coursecat $category = null) {
5dc361e1 321 $actions = array();
017518d4
SH
322
323 $cancreatecategory = $category && $category->can_create_subcategory();
324 $cancreatecategory = $cancreatecategory || coursecat::can_create_top_level_category();
b488058f
SH
325 if ($category === null) {
326 $category = coursecat::get(0);
327 }
5dc361e1 328
017518d4
SH
329 if ($cancreatecategory) {
330 $url = new moodle_url('/course/editcategory.php', array('parent' => $category->id));
331 $actions[] = html_writer::link($url, get_string('createnewcategory'));
5dc361e1 332 }
484c4c6c
SH
333 if (coursecat::can_approve_course_requests()) {
334 $actions[] = html_writer::link(new moodle_url('/course/pending.php'), get_string('coursespending'));
335 }
c7a2291f 336 if (count($actions) === 0) {
5dc361e1
SH
337 return '';
338 }
339 return html_writer::div(join(' | ', $actions), 'listing-actions category-listing-actions');
340 }
341
342 /**
343 * Renderers the actions for individual category list items.
344 *
345 * @param coursecat $category
c7a2291f 346 * @param array $actions
5dc361e1
SH
347 * @return string
348 */
b488058f
SH
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);
352 }
5dc361e1
SH
353 $menu = new action_menu();
354 $menu->attributes['class'] .= ' category-item-actions item-actions';
355 $hasitems = false;
b488058f 356 foreach ($actions as $key => $action) {
5dc361e1
SH
357 $hasitems = true;
358 $menu->add(new action_menu_link(
359 $action['url'],
360 $action['icon'],
361 $action['string'],
362 in_array($key, array('show', 'hide', 'moveup', 'movedown')),
363 array('data-action' => $key, 'class' => 'action-'.$key)
364 ));
365 }
366 if (!$hasitems) {
367 return '';
368 }
369 return $this->render($menu);
370 }
371
372 /**
373 * Renders bulk actions for categories.
374 *
c7a2291f 375 * @param coursecat $category The currently selected category if there is one.
5dc361e1
SH
376 * @return string
377 */
c7a2291f 378 public function category_bulk_actions(coursecat $category = null) {
5dc361e1
SH
379 // Resort courses.
380 // Change parent.
cd96b7d3
SH
381 if (!coursecat::can_resort_any() && !coursecat::can_change_parent_any()) {
382 return '';
383 }
5dc361e1
SH
384 $strgo = new lang_string('go');
385
386 $html = html_writer::start_div('category-bulk-actions bulk-actions');
cd96b7d3 387 $html .= html_writer::div(get_string('categorybulkaction'), 'accesshide', array('tabindex' => '0'));
5dc361e1 388 if (coursecat::can_resort_any()) {
c7a2291f
SH
389 $selectoptions = array(
390 'selectedcategories' => get_string('selectedcategories'),
391 'allcategories' => get_string('allcategories')
5dc361e1 392 );
c7a2291f
SH
393 $form = html_writer::start_div();
394 if ($category) {
395 $selectoptions = array('thiscategory' => get_string('thiscategory')) + $selectoptions;
396 $form .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'currentcategoryid', 'value' => $category->id));
397 }
398 $form .= html_writer::div(
c7a2291f
SH
399 html_writer::select(
400 $selectoptions,
401 'selectsortby',
e69a0251 402 'selectedcategories',
d0647301
SH
403 false,
404 array('aria-label' => get_string('selectcategorysort'))
c7a2291f 405 )
7fd307b1 406 );
c7a2291f 407 $form .= html_writer::div(
c7a2291f
SH
408 html_writer::select(
409 array(
e69a0251
SH
410 'name' => get_string('sortcategoriesbyname'),
411 'idnumber' => get_string('sortcategoriesbyidnumber'),
c7a2291f
SH
412 'none' => get_string('dontsortcategories')
413 ),
414 'resortcategoriesby',
e69a0251 415 'name',
d0647301
SH
416 false,
417 array('aria-label' => get_string('selectcategorysortby'))
c7a2291f
SH
418 )
419 );
420 $form .= html_writer::div(
c7a2291f
SH
421 html_writer::select(
422 array(
e69a0251
SH
423 'fullname' => get_string('sortcoursesbyfullname'),
424 'shortname' => get_string('sortcoursesbyshortname'),
425 'idnumber' => get_string('sortcoursesbyidnumber'),
c7a2291f
SH
426 'none' => get_string('dontsortcourses')
427 ),
428 'resortcoursesby',
e69a0251 429 'fullname',
d0647301
SH
430 false,
431 array('aria-label' => get_string('selectcoursesortby'))
c7a2291f 432 )
7fd307b1 433 );
e69a0251 434 $form .= html_writer::empty_tag('input', array('type' => 'submit', 'name' => 'bulksort', 'value' => get_string('sort')));
c7a2291f 435 $form .= html_writer::end_div();
d0647301
SH
436
437 $html .= html_writer::start_div('detail-pair row yui3-g');
438 $html .= html_writer::div(html_writer::span(get_string('sorting')), 'pair-key span3 yui3-u-1-4');
439 $html .= html_writer::div($form, 'pair-value span9 yui3-u-3-4');
440 $html .= html_writer::end_div();
5dc361e1
SH
441 }
442 if (coursecat::can_change_parent_any()) {
3b732cd6
RT
443 $options = array();
444 if (has_capability('moodle/category:manage', context_system::instance())) {
445 $options[0] = coursecat::get(0)->get_formatted_name();
446 }
447 $options += coursecat::make_categories_list('moodle/category:manage');
7fd307b1
SH
448 $select = html_writer::select(
449 $options,
450 'movecategoriesto',
451 '',
452 array('' => 'choosedots'),
453 array('aria-labelledby' => 'moveselectedcategoriesto')
454 );
e69a0251 455 $submit = array('type' => 'submit', 'name' => 'bulkmovecategories', 'value' => get_string('move'));
5dc361e1 456 $html .= $this->detail_pair(
7fd307b1 457 html_writer::span(get_string('moveselectedcategoriesto'), '', array('id' => 'moveselectedcategoriesto')),
5dc361e1
SH
458 $select . html_writer::empty_tag('input', $submit)
459 );
460 }
461 $html .= html_writer::end_div();
462 return $html;
463 }
464
465 /**
466 * Renders a course listing.
467 *
468 * @param coursecat $category The currently selected category. This is what the listing is focused on.
469 * @param course_in_list $course The currently selected course.
470 * @param int $page The page being displayed.
471 * @param int $perpage The number of courses to display per page.
472 * @return string
473 */
474 public function course_listing(coursecat $category = null, course_in_list $course = null, $page = 0, $perpage = 20) {
475
476 if ($category === null) {
477 $html = html_writer::start_div('select-a-category');
d0647301
SH
478 $html .= html_writer::tag('h3', get_string('courses'),
479 array('id' => 'course-listing-title', 'tabindex' => '0'));
5dc361e1
SH
480 $html .= $this->output->notification(get_string('selectacategory'), 'notifymessage');
481 $html .= html_writer::end_div();
482 return $html;
483 }
484
485 $page = max($page, 0);
486 $perpage = max($perpage, 2);
487 $totalcourses = $category->coursecount;
488 $totalpages = ceil($totalcourses / $perpage);
489 if ($page > $totalpages - 1) {
490 $page = $totalpages - 1;
491 }
492 $options = array(
493 'offset' => $page * $perpage,
494 'limit' => $perpage
495 );
496 $courseid = isset($course) ? $course->id : null;
484c4c6c
SH
497 $class = '';
498 if ($page === 0) {
499 $class .= ' firstpage';
500 }
501 if ($page + 1 === (int)$totalpages) {
502 $class .= ' lastpage';
503 }
5dc361e1 504
484c4c6c 505 $html = html_writer::start_div('course-listing'.$class, array(
5dc361e1
SH
506 'data-category' => $category->id,
507 'data-page' => $page,
508 'data-totalpages' => $totalpages,
509 'data-totalcourses' => $totalcourses,
510 'data-canmoveoutof' => $category->can_move_courses_out_of() && $category->can_move_courses_into()
511 ));
d0647301
SH
512 $html .= html_writer::tag('h3', $category->get_formatted_name(),
513 array('id' => 'course-listing-title', 'tabindex' => '0'));
5dc361e1
SH
514 $html .= $this->course_listing_actions($category, $course, $perpage);
515 $html .= $this->listing_pagination($category, $page, $perpage);
d0647301 516 $html .= html_writer::start_tag('ul', array('class' => 'ml', 'role' => 'group'));
5dc361e1 517 foreach ($category->get_courses($options) as $listitem) {
f454e324 518 $html .= $this->course_listitem($category, $listitem, $courseid);
5dc361e1
SH
519 }
520 $html .= html_writer::end_tag('ul');
521 $html .= $this->listing_pagination($category, $page, $perpage, true);
522 $html .= $this->course_bulk_actions($category);
523 $html .= html_writer::end_div();
524 return $html;
525 }
526
527 /**
528 * Renders pagination for a course listing.
529 *
530 * @param coursecat $category The category to produce pagination for.
531 * @param int $page The current page.
532 * @param int $perpage The number of courses to display per page.
533 * @param bool $showtotals Set to true to show the total number of courses and what is being displayed.
534 * @return string
535 */
536 protected function listing_pagination(coursecat $category, $page, $perpage, $showtotals = false) {
537 $html = '';
d61d3163 538 $totalcourses = $category->get_courses_count();
5dc361e1
SH
539 $totalpages = ceil($totalcourses / $perpage);
540 if ($showtotals) {
541 if ($totalpages == 0) {
542 $str = get_string('nocoursesyet');
543 } else if ($totalpages == 1) {
544 $str = get_string('showingacourses', 'moodle', $totalcourses);
545 } else {
546 $a = new stdClass;
547 $a->start = ($page * $perpage) + 1;
548 $a->end = min((($page + 1) * $perpage), $totalcourses);
549 $a->total = $totalcourses;
550 $str = get_string('showingxofycourses', 'moodle', $a);
551 }
552 $html .= html_writer::div($str, 'listing-pagination-totals dimmed');
553 }
554
7c033254 555 if ($totalcourses <= $perpage) {
5dc361e1
SH
556 return $html;
557 }
558 $aside = 2;
559 $span = $aside * 2 + 1;
560 $start = max($page - $aside, 0);
561 $end = min($page + $aside, $totalpages - 1);
562 if (($end - $start) < $span) {
563 if ($start == 0) {
564 $end = min($totalpages - 1, $span - 1);
565 } else if ($end == ($totalpages - 1)) {
566 $start = max(0, $end - $span + 1);
567 }
568 }
569 $items = array();
570 $baseurl = new moodle_url('/course/management.php', array('categoryid' => $category->id));
571 if ($page > 0) {
572 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => 0)), get_string('first'));
573 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $page - 1)), get_string('prev'));
574 $items[] = '...';
575 }
576 for ($i = $start; $i <= $end; $i++) {
577 $class = '';
578 if ($page == $i) {
579 $class = 'active-page';
580 }
7fd307b1
SH
581 $pageurl = new moodle_url($baseurl, array('page' => $i));
582 $items[] = $this->action_button($pageurl, $i + 1, null, $class, get_string('pagea', 'moodle', $i+1));
5dc361e1
SH
583 }
584 if ($page < ($totalpages - 1)) {
585 $items[] = '...';
586 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $page + 1)), get_string('next'));
587 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $totalpages - 1)), get_string('last'));
588 }
589
590 $html .= html_writer::div(join('', $items), 'listing-pagination');
591 return $html;
592 }
593
594 /**
595 * Renderers a course list item.
596 *
597 * This function will be called for every course being displayed by course_listing.
598 *
599 * @param coursecat $category The currently selected category and the category the course belongs to.
600 * @param course_in_list $course The course to produce HTML for.
601 * @param int $selectedcourse The id of the currently selected course.
5dc361e1
SH
602 * @return string
603 */
f454e324 604 public function course_listitem(coursecat $category, course_in_list $course, $selectedcourse) {
5dc361e1
SH
605
606 $text = $course->get_formatted_name();
607 $attributes = array(
608 'class' => 'listitem listitem-course',
609 'data-id' => $course->id,
610 'data-selected' => ($selectedcourse == $course->id) ? '1' : '0',
611 'data-visible' => $course->visible ? '1' : '0'
612 );
613
d0647301
SH
614 $bulkcourseinput = array(
615 'type' => 'checkbox',
616 'name' => 'bc[]',
617 'value' => $course->id,
618 'class' => 'bulk-action-checkbox',
a5888fb5
RT
619 'aria-label' => get_string('bulkactionselect', 'moodle', $text),
620 'data-action' => 'select'
d0647301 621 );
484c4c6c
SH
622 if (!$category->has_manage_capability()) {
623 // Very very hardcoded here.
624 $bulkcourseinput['style'] = 'visibility:hidden';
625 }
626
5dc361e1
SH
627 $viewcourseurl = new moodle_url($this->page->url, array('courseid' => $course->id));
628
629 $html = html_writer::start_tag('li', $attributes);
630 $html .= html_writer::start_div('clearfix');
631
67e1f268 632 if ($category->can_resort_courses()) {
5dc361e1 633 // In order for dnd to be available the user must be able to resort the category children..
10a2bf46 634 $html .= html_writer::div($this->output->pix_icon('i/move_2d', get_string('dndcourse')), 'float-left drag-handle');
5dc361e1
SH
635 }
636
3b681e6c 637 $html .= html_writer::start_div('ba-checkbox float-left');
7fd307b1 638 $html .= html_writer::empty_tag('input', $bulkcourseinput).'&nbsp;';
5dc361e1
SH
639 $html .= html_writer::end_div();
640 $html .= html_writer::link($viewcourseurl, $text, array('class' => 'float-left coursename'));
641 $html .= html_writer::start_div('float-right');
c7a2291f
SH
642 if ($course->idnumber) {
643 $html .= html_writer::tag('span', s($course->idnumber), array('class' => 'dimmed idnumber'));
644 }
f454e324 645 $html .= $this->course_listitem_actions($category, $course);
5dc361e1
SH
646 $html .= html_writer::end_div();
647 $html .= html_writer::end_div();
648 $html .= html_writer::end_tag('li');
649 return $html;
650 }
651
652 /**
653 * Renderers actions for the course listing.
654 *
655 * Not to be confused with course_listitem_actions which renderers the actions for individual courses.
656 *
657 * @param coursecat $category
658 * @param course_in_list $course The currently selected course.
659 * @param int $perpage
660 * @return string
661 */
662 public function course_listing_actions(coursecat $category, course_in_list $course = null, $perpage = 20) {
663 $actions = array();
664 if ($category->can_create_course()) {
665 $url = new moodle_url('/course/edit.php', array('category' => $category->id, 'returnto' => 'catmanage'));
d3670843 666 $actions[] = html_writer::link($url, get_string('createnewcourse'));
5dc361e1 667 }
484c4c6c
SH
668 if ($category->can_request_course()) {
669 // Request a new course.
670 $url = new moodle_url('/course/request.php', array('return' => 'management'));
671 $actions[] = html_writer::link($url, get_string('requestcourse'));
672 }
67e1f268 673 if ($category->can_resort_courses()) {
5dc361e1
SH
674 $params = $this->page->url->params();
675 $params['action'] = 'resortcourses';
676 $params['sesskey'] = sesskey();
677 $baseurl = new moodle_url('/course/management.php', $params);
678 $fullnameurl = new moodle_url($baseurl, array('resort' => 'fullname'));
679 $shortnameurl = new moodle_url($baseurl, array('resort' => 'shortname'));
680 $idnumberurl = new moodle_url($baseurl, array('resort' => 'idnumber'));
681 $menu = new action_menu(array(
682 new action_menu_link_secondary($fullnameurl, null, get_string('resortbyfullname')),
683 new action_menu_link_secondary($shortnameurl, null, get_string('resortbyshortname')),
684 new action_menu_link_secondary($idnumberurl, null, get_string('resortbyidnumber'))
685 ));
f5b33487 686 $menu->set_menu_trigger(get_string('resortcourses'));
5dc361e1
SH
687 $actions[] = $this->render($menu);
688 }
689 $strall = get_string('all');
690 $menu = new action_menu(array(
691 new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 5)), null, 5),
692 new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 10)), null, 10),
693 new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 20)), null, 20),
694 new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 50)), null, 50),
695 new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 100)), null, 100),
696 new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 999)), null, $strall),
697 ));
7fd307b1 698 if ((int)$perpage === 999) {
5dc361e1
SH
699 $perpage = $strall;
700 }
701 $menu->attributes['class'] .= ' courses-per-page';
f5b33487 702 $menu->set_menu_trigger(get_string('perpagea', 'moodle', $perpage));
5dc361e1
SH
703 $actions[] = $this->render($menu);
704 return html_writer::div(join(' | ', $actions), 'listing-actions course-listing-actions');
705 }
706
707 /**
708 * Renderers actions for individual course actions.
709 *
710 * @param coursecat $category The currently selected category.
711 * @param course_in_list $course The course to renderer actions for.
5dc361e1
SH
712 * @return string
713 */
f454e324 714 public function course_listitem_actions(coursecat $category, course_in_list $course) {
484c4c6c 715 $actions = \core_course\management\helper::get_course_listitem_actions($category, $course);
5dc361e1
SH
716 if (empty($actions)) {
717 return '';
718 }
484c4c6c
SH
719 $actionshtml = array();
720 foreach ($actions as $action) {
7fd307b1 721 $action['attributes']['role'] = 'button';
484c4c6c
SH
722 $actionshtml[] = $this->output->action_icon($action['url'], $action['icon'], null, $action['attributes']);
723 }
724 return html_writer::span(join('', $actionshtml), 'course-item-actions item-actions');
5dc361e1
SH
725 }
726
727 /**
728 * Renderers bulk actions that can be performed on courses.
729 *
730 * @param coursecat $category The currently selected category and the category in which courses that
731 * are selectable belong.
732 * @return string
733 */
734 public function course_bulk_actions(coursecat $category) {
735 $html = html_writer::start_div('course-bulk-actions bulk-actions');
736 if ($category->can_move_courses_out_of()) {
cd96b7d3 737 $html .= html_writer::div(get_string('coursebulkaction'), 'accesshide', array('tabindex' => '0'));
5dc361e1 738 $options = coursecat::make_categories_list('moodle/category:manage');
7fd307b1
SH
739 $select = html_writer::select(
740 $options,
741 'movecoursesto',
742 '',
743 array('' => 'choosedots'),
744 array('aria-labelledby' => 'moveselectedcoursesto')
745 );
e69a0251 746 $submit = array('type' => 'submit', 'name' => 'bulkmovecourses', 'value' => get_string('move'));
5dc361e1 747 $html .= $this->detail_pair(
7fd307b1 748 html_writer::span(get_string('moveselectedcoursesto'), '', array('id' => 'moveselectedcoursesto')),
5dc361e1
SH
749 $select . html_writer::empty_tag('input', $submit)
750 );
751 }
752 $html .= html_writer::end_div();
753 return $html;
754 }
755
756 /**
757 * Renderers detailed course information.
758 *
759 * @param course_in_list $course The course to display details for.
760 * @return string
761 */
762 public function course_detail(course_in_list $course) {
763 $details = \core_course\management\helper::get_course_detail_array($course);
764 $fullname = $details['fullname']['value'];
765
766 $html = html_writer::start_div('course-detail');
d0647301 767 $html .= html_writer::tag('h3', $fullname, array('id' => 'course-detail-title', 'tabindex' => '0'));
5dc361e1
SH
768 $html .= $this->course_detail_actions($course);
769 foreach ($details as $class => $data) {
770 $html .= $this->detail_pair($data['key'], $data['value'], $class);
771 }
772 $html .= html_writer::end_div();
773 return $html;
774 }
775
776 /**
777 * Renderers a key value pair of information for display.
778 *
779 * @param string $key
780 * @param string $value
781 * @param string $class
782 * @return string
783 */
784 protected function detail_pair($key, $value, $class ='') {
484c4c6c
SH
785 $html = html_writer::start_div('detail-pair row yui3-g '.preg_replace('#[^a-zA-Z0-9_\-]#', '-', $class));
786 $html .= html_writer::div(html_writer::span($key), 'pair-key span3 yui3-u-1-4');
787 $html .= html_writer::div(html_writer::span($value), 'pair-value span9 yui3-u-3-4');
5dc361e1
SH
788 $html .= html_writer::end_div();
789 return $html;
790 }
791
792 /**
793 * A collection of actions for a course.
794 *
795 * @param course_in_list $course The course to display actions for.
796 * @return string
797 */
798 public function course_detail_actions(course_in_list $course) {
799 $actions = \core_course\management\helper::get_course_detail_actions($course);
800 if (empty($actions)) {
801 return '';
802 }
803 $options = array();
804 foreach ($actions as $action) {
484c4c6c 805 $options[] = $this->action_link($action['url'], $action['string']);
5dc361e1 806 }
484c4c6c 807 return html_writer::div(join(' | ', $options), 'listing-actions course-detail-listing-actions');
5dc361e1
SH
808 }
809
810 /**
811 * Creates an action button (styled link)
812 *
813 * @param moodle_url $url The URL to go to when clicked.
814 * @param string $text The text for the button.
815 * @param string $id An id to give the button.
816 * @param string $class A class to give the button.
d0647301 817 * @param array $attributes Any additional attributes
5dc361e1
SH
818 * @return string
819 */
d0647301
SH
820 protected function action_button(moodle_url $url, $text, $id = null, $class = null, $title = null, array $attributes = array()) {
821 if (isset($attributes['class'])) {
822 $attributes['class'] .= ' yui3-button';
823 } else {
824 $attributes['class'] = 'yui3-button';
825 }
5dc361e1
SH
826 if (!is_null($id)) {
827 $attributes['id'] = $id;
828 }
829 if (!is_null($class)) {
830 $attributes['class'] .= ' '.$class;
831 }
7fd307b1
SH
832 if (is_null($title)) {
833 $title = $text;
834 }
835 $attributes['title'] = $title;
d0647301
SH
836 if (!isset($attributes['role'])) {
837 $attributes['role'] = 'button';
838 }
5dc361e1
SH
839 return html_writer::link($url, $text, $attributes);
840 }
841
842 /**
843 * Opens a grid.
844 *
845 * Call {@link core_course_management_renderer::grid_column_start()} to create columns.
846 *
847 * @param string $id An id to give this grid.
848 * @param string $class A class to give this grid.
849 * @return string
850 */
851 public function grid_start($id = null, $class = null) {
852 $gridclass = 'grid-row-r row-fluid';
853 if (is_null($class)) {
854 $class = $gridclass;
855 } else {
856 $class .= ' ' . $gridclass;
857 }
858 $attributes = array();
859 if (!is_null($id)) {
860 $attributes['id'] = $id;
861 }
862 return html_writer::start_div($class, $attributes);
863 }
864
865 /**
866 * Closes the grid.
867 *
868 * @return string
869 */
870 public function grid_end() {
871 return html_writer::end_div();
872 }
873
874 /**
875 * Opens a grid column
876 *
877 * @param int $size The number of segments this column should span.
878 * @param string $id An id to give the column.
879 * @param string $class A class to give the column.
880 * @return string
881 */
882 public function grid_column_start($size, $id = null, $class = null) {
883
884 // Calculate Bootstrap grid sizing.
885 $bootstrapclass = 'span'.$size;
886
887 // Calculate YUI grid sizing.
888 if ($size === 12) {
889 $maxsize = 1;
890 $size = 1;
891 } else {
892 $maxsize = 12;
893 $divisors = array(8, 6, 5, 4, 3, 2);
894 foreach ($divisors as $divisor) {
895 if (($maxsize % $divisor === 0) && ($size % $divisor === 0)) {
896 $maxsize = $maxsize / $divisor;
897 $size = $size / $divisor;
898 break;
899 }
900 }
901 }
902 if ($maxsize > 1) {
903 $yuigridclass = "grid-col-{$size}-{$maxsize} grid-col";
904 } else {
905 $yuigridclass = "grid-col-1 grid-col";
906 }
907
908 if (is_null($class)) {
909 $class = $yuigridclass . ' ' . $bootstrapclass;
910 } else {
911 $class .= ' ' . $yuigridclass . ' ' . $bootstrapclass;
912 }
913 $attributes = array();
914 if (!is_null($id)) {
915 $attributes['id'] = $id;
916 }
917 return html_writer::start_div($class, $attributes);
918 }
919
920 /**
921 * Closes a grid column.
922 *
923 * @return string
924 */
925 public function grid_column_end() {
926 return html_writer::end_div();
927 }
928
929 /**
930 * Renders an action_icon.
931 *
932 * This function uses the {@link core_renderer::action_link()} method for the
933 * most part. What it does different is prepare the icon as HTML and use it
934 * as the link text.
935 *
936 * @param string|moodle_url $url A string URL or moodel_url
937 * @param pix_icon $pixicon
938 * @param component_action $action
939 * @param array $attributes associative array of html link attributes + disabled
940 * @param bool $linktext show title next to image in link
941 * @return string HTML fragment
942 */
943 public function action_icon($url, pix_icon $pixicon, component_action $action = null,
944 array $attributes = null, $linktext = false) {
945 if (!($url instanceof moodle_url)) {
946 $url = new moodle_url($url);
947 }
948 $attributes = (array)$attributes;
949
950 if (empty($attributes['class'])) {
951 // Let devs override the class via $attributes.
952 $attributes['class'] = 'action-icon';
953 }
954
955 $icon = $this->render($pixicon);
956
957 if ($linktext) {
958 $text = $pixicon->attributes['alt'];
959 } else {
960 $text = '';
961 }
962
963 return $this->action_link($url, $icon.$text, $action, $attributes);
964 }
965
966 /**
967 * Displays a view mode selector.
968 *
969 * @param array $modes An array of view modes.
970 * @param string $currentmode The current view mode.
971 * @param moodle_url $url The URL to use when changing actions. Defaults to the page URL.
972 * @param string $param The param name.
973 * @return string
974 */
975 public function view_mode_selector(array $modes, $currentmode, moodle_url $url = null, $param = 'view') {
976 if ($url === null) {
977 $url = $this->page->url;
978 }
979
980 $menu = new action_menu;
981 $menu->attributes['class'] .= ' view-mode-selector vms';
982
983 $selected = null;
984 foreach ($modes as $mode => $modestr) {
985 $attributes = array(
986 'class' => 'vms-mode',
987 'data-mode' => $mode
988 );
989 if ($currentmode === $mode) {
990 $attributes['class'] .= ' currentmode';
991 $selected = $modestr;
992 }
993 if ($selected === null) {
994 $selected = $modestr;
995 }
996 $modeurl = new moodle_url($url, array($param => $mode));
997 if ($mode === 'default') {
998 $modeurl->remove_params($param);
999 }
1000 $menu->add(new action_menu_link_secondary($modeurl, null, $modestr, $attributes));
1001 }
1002
aa861f62 1003 $menu->set_menu_trigger($selected);
5dc361e1
SH
1004
1005 $html = html_writer::start_div('view-mode-selector vms');
aa861f62 1006 $html .= get_string('viewing').' '.$this->render($menu);
5dc361e1
SH
1007 $html .= html_writer::end_div();
1008
1009 return $html;
1010 }
1011
1012 /**
1013 * Displays a search result listing.
1014 *
1015 * @param array $courses The courses to display.
1016 * @param int $totalcourses The total number of courses to display.
1017 * @param course_in_list $course The currently selected course if there is one.
1018 * @param int $page The current page, starting at 0.
1019 * @param int $perpage The number of courses to display per page.
1020 * @return string
1021 */
1022 public function search_listing(array $courses, $totalcourses, course_in_list $course = null, $page = 0, $perpage = 20) {
1023 $page = max($page, 0);
1024 $perpage = max($perpage, 2);
1025 $totalpages = ceil($totalcourses / $perpage);
1026 if ($page > $totalpages - 1) {
1027 $page = $totalpages - 1;
1028 }
1029 $courseid = isset($course) ? $course->id : null;
1030 $first = true;
1031 $last = false;
1032 $i = $page * $perpage;
1033
1034 $html = html_writer::start_div('course-listing', array(
1035 'data-category' => 'search',
1036 'data-page' => $page,
1037 'data-totalpages' => $totalpages,
1038 'data-totalcourses' => $totalcourses
1039 ));
1040 $html .= html_writer::tag('h3', get_string('courses'));
1041 $html .= $this->search_pagination($totalcourses, $page, $perpage);
1042 $html .= html_writer::start_tag('ul', array('class' => 'ml'));
1043 foreach ($courses as $listitem) {
1044 $i++;
1045 if ($i == $totalcourses) {
1046 $last = true;
1047 }
1048 $html .= $this->search_listitem($listitem, $courseid, $first, $last);
1049 $first = false;
1050 }
1051 $html .= html_writer::end_tag('ul');
1052 $html .= $this->search_pagination($totalcourses, $page, $perpage, true);
1053 $html .= html_writer::end_div();
1054 return $html;
1055 }
1056
1057 /**
1058 * Displays pagination for search results.
1059 *
1060 * @param int $totalcourses The total number of courses to be displayed.
1061 * @param int $page The current page.
1062 * @param int $perpage The number of courses being displayed.
1063 * @param bool $showtotals Whether or not to print total information.
1064 * @return string
1065 */
1066 protected function search_pagination($totalcourses, $page, $perpage, $showtotals = false) {
1067 $html = '';
1068 $totalpages = ceil($totalcourses / $perpage);
1069 if ($showtotals) {
1070 if ($totalpages == 1) {
1071 $str = get_string('showingacourses', 'moodle', $totalcourses);
1072 } else {
1073 $a = new stdClass;
1074 $a->start = ($page * $perpage) + 1;
1075 $a->end = min((($page + 1) * $perpage), $totalcourses);
1076 $a->total = $totalcourses;
1077 $str = get_string('showingxofycourses', 'moodle', $a);
1078 }
1079 $html .= html_writer::div($str, 'listing-pagination-totals dimmed');
1080 }
1081
1082 if ($totalcourses < $perpage) {
1083 return $html;
1084 }
1085 $aside = 2;
1086 $span = $aside * 2 + 1;
1087 $start = max($page - $aside, 0);
1088 $end = min($page + $aside, $totalpages - 1);
1089 if (($end - $start) < $span) {
1090 if ($start == 0) {
1091 $end = min($totalpages - 1, $span - 1);
1092 } else if ($end == ($totalpages - 1)) {
1093 $start = max(0, $end - $span + 1);
1094 }
1095 }
1096 $items = array();
1097 $baseurl = $this->page->url;
1098 if ($page > 0) {
1099 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => 0)), get_string('first'));
1100 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $page - 1)), get_string('prev'));
1101 $items[] = '...';
1102 }
1103 for ($i = $start; $i <= $end; $i++) {
1104 $class = '';
1105 if ($page == $i) {
1106 $class = 'active-page';
1107 }
1108 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $i)), $i + 1, null, $class);
1109 }
1110 if ($page < ($totalpages - 1)) {
1111 $items[] = '...';
1112 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $page + 1)), get_string('next'));
1113 $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $totalpages - 1)), get_string('last'));
1114 }
1115
1116 $html .= html_writer::div(join('', $items), 'listing-pagination');
1117 return $html;
1118 }
1119
1120 /**
1121 * Renderers a search result course list item.
1122 *
1123 * This function will be called for every course being displayed by course_listing.
1124 *
1125 * @param course_in_list $course The course to produce HTML for.
1126 * @param int $selectedcourse The id of the currently selected course.
1127 * @return string
1128 */
1129 public function search_listitem(course_in_list $course, $selectedcourse) {
1130
1131 $text = $course->get_formatted_name();
1132 $attributes = array(
1133 'class' => 'listitem listitem-course',
1134 'data-id' => $course->id,
1135 'data-selected' => ($selectedcourse == $course->id) ? '1' : '0',
1136 'data-visible' => $course->visible ? '1' : '0'
1137 );
1138
1139 $bulkcourseinput = array('type' => 'checkbox', 'name' => 'bc[]', 'value' => $course->id, 'class' => 'bulk-action-checkbox');
1140 $viewcourseurl = new moodle_url($this->page->url, array('courseid' => $course->id));
1141 $categoryname = coursecat::get($course->category)->get_formatted_name();
1142
1143 $html = html_writer::start_tag('li', $attributes);
1144 $html .= html_writer::start_div('clearfix');
1145 $html .= html_writer::start_div('float-left');
7fd307b1 1146 $html .= html_writer::empty_tag('input', $bulkcourseinput).'&nbsp;';
5dc361e1
SH
1147 $html .= html_writer::end_div();
1148 $html .= html_writer::link($viewcourseurl, $text, array('class' => 'float-left coursename'));
1149 $html .= html_writer::tag('span', $categoryname, array('class' => 'float-left categoryname'));
1150 $html .= html_writer::start_div('float-right');
1151 $html .= $this->search_listitem_actions($course);
1152 $html .= html_writer::tag('span', s($course->idnumber), array('class' => 'dimmed idnumber'));
1153 $html .= html_writer::end_div();
1154 $html .= html_writer::end_div();
1155 $html .= html_writer::end_tag('li');
1156 return $html;
1157 }
1158
1159 /**
1160 * Renderers actions for individual course actions.
1161 *
1162 * @param course_in_list $course The course to renderer actions for.
1163 * @return string
1164 */
1165 public function search_listitem_actions(course_in_list $course) {
1166 $baseurl = new moodle_url(
1167 '/course/managementsearch.php',
1168 array('courseid' => $course->id, 'categoryid' => $course->category, 'sesskey' => sesskey())
1169 );
1170 $actions = array();
1171 // Edit.
484c4c6c
SH
1172 if ($course->can_access()) {
1173 if ($course->can_edit()) {
5dc361e1 1174 $actions[] = $this->output->action_icon(
484c4c6c
SH
1175 new moodle_url('/course/edit.php', array('id' => $course->id)),
1176 new pix_icon('t/edit', get_string('edit')),
5dc361e1 1177 null,
484c4c6c 1178 array('class' => 'action-edit')
5dc361e1
SH
1179 );
1180 }
484c4c6c
SH
1181 // Show/Hide.
1182 if ($course->can_change_visibility()) {
1183 if ($course->visible) {
1184 $actions[] = $this->output->action_icon(
1185 new moodle_url($baseurl, array('action' => 'hidecourse')),
1186 new pix_icon('t/show', get_string('hide')),
1187 null,
1188 array('data-action' => 'hide', 'class' => 'action-hide')
1189 );
1190 } else {
1191 $actions[] = $this->output->action_icon(
1192 new moodle_url($baseurl, array('action' => 'showcourse')),
1193 new pix_icon('t/hide', get_string('show')),
1194 null,
1195 array('data-action' => 'show', 'class' => 'action-show')
1196 );
1197 }
1198 }
5dc361e1
SH
1199 }
1200 if (empty($actions)) {
1201 return '';
1202 }
1203 return html_writer::span(join('', $actions), 'course-item-actions item-actions');
1204 }
1205
d0647301
SH
1206 /**
1207 * Creates access hidden skip to links for the displayed sections.
1208 *
1209 * @param bool $displaycategorylisting
1210 * @param bool $displaycourselisting
1211 * @param bool $displaycoursedetail
1212 * @return string
1213 */
1214 public function accessible_skipto_links($displaycategorylisting, $displaycourselisting, $displaycoursedetail) {
1215 $html = html_writer::start_div('skiplinks accesshide');
1216 $url = new moodle_url($this->page->url);
1217 if ($displaycategorylisting) {
1218 $url->set_anchor('category-listing');
1219 $html .= html_writer::link($url, get_string('skiptocategorylisting'), array('class' => 'skip'));
1220 }
cd96b7d3 1221 if ($displaycourselisting) {
d0647301
SH
1222 $url->set_anchor('course-listing');
1223 $html .= html_writer::link($url, get_string('skiptocourselisting'), array('class' => 'skip'));
1224 }
cd96b7d3 1225 if ($displaycoursedetail) {
d0647301
SH
1226 $url->set_anchor('course-detail');
1227 $html .= html_writer::link($url, get_string('skiptocoursedetails'), array('class' => 'skip'));
1228 }
1229 $html .= html_writer::end_div();
1230 return $html;
1231 }
1232
9e164027 1233}