MDL-58428 renderer: Move renderer override from files
[moodle.git] / course / classes / management_renderer.php
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/>.
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  */
25 defined('MOODLE_INTERNAL') || die;
27 require_once($CFG->dirroot.'/course/renderer.php');
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  */
36 class core_course_management_renderer extends plugin_renderer_base {
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() {
45         $this->page->requires->yui_module('moodle-course-management', 'M.course.management.init');
46         $this->page->requires->strings_for_js(
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             ),
60             'moodle'
61         );
62     }
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) {
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 = core_course_category::make_categories_list(array('moodle/category:manage', 'moodle/course:create'));
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             }
90             $html .= html_writer::end_div();
91         }
92         $html .= html_writer::end_div();
93         return $html;
94     }
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');
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     }
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     }
119     /**
120      * Presents a course category listing.
121      *
122      * @param core_course_category $category The currently selected category. Also the category to highlight in the listing.
123      * @return string
124      */
125     public function category_listing(core_course_category $category = null) {
127         if ($category === null) {
128             $selectedparents = array();
129             $selectedcategory = null;
130         } else {
131             $selectedparents = $category->get_parents();
132             $selectedparents[] = $category->id;
133             $selectedcategory = $category->id;
134         }
135         $catatlevel = \core_course\management\helper::get_expanded_categories('');
136         $catatlevel[] = array_shift($selectedparents);
137         $catatlevel = array_unique($catatlevel);
139         $listing = core_course_category::get(0)->get_children();
141         $attributes = array(
142             'class' => 'ml',
143             'role' => 'tree',
144             'aria-labelledby' => 'category-listing-title'
145         );
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();
156             }
157             $html .= $this->category_listitem(
158                 $listitem,
159                 $subcategories,
160                 $listitem->get_children_count(),
161                 $selectedcategory,
162                 $selectedparents
163             );
164         }
165         $html .= html_writer::end_tag('ul');
166         $html .= $this->category_bulk_actions($category);
167         $html .= html_writer::end_div();
168         return $html;
169     }
171     /**
172      * Renders a category list item.
173      *
174      * This function gets called recursively to render sub categories.
175      *
176      * @param core_course_category $category The category to render as listitem.
177      * @param core_course_category[] $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(core_course_category $category, array $subcategories, $totalsubcategories,
184                                       $selectedcategory = null, $selectedcategories = array()) {
186         $isexpandable = ($totalsubcategories > 0);
187         $isexpanded = (!empty($subcategories));
188         $activecategory = ($selectedcategory === $category->id);
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',
195             'data-visible' => $category->visible ? '1' : '0',
196             'role' => 'treeitem',
197             'aria-expanded' => $isexpanded ? 'true' : 'false'
198         );
199         $text = $category->get_formatted_name();
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         }
206         $courseicon = $this->output->pix_icon('i/course', get_string('courses'));
207         $bcatinput = array(
208             'type' => 'checkbox',
209             'name' => 'bcat[]',
210             'value' => $category->id,
211             'class' => 'bulk-action-checkbox',
212             'aria-label' => get_string('bulkactionselect', 'moodle', $text),
213             'data-action' => 'select'
214         );
216         if (!$category->can_resort_subcategories() && !$category->has_manage_capability()) {
217             // Very very hardcoded here.
218             $bcatinput['style'] = 'visibility:hidden';
219         }
221         $viewcaturl = new moodle_url('/course/management.php', array('categoryid' => $category->id));
222         if ($isexpanded) {
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             );
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(
237                 $viewcaturl,
238                 $icon,
239                 array(
240                     'class' => 'float-left',
241                     'data-action' => 'expand',
242                     'title' => get_string('expandcategory', 'moodle', $text)
243                 )
244             );
245         } else {
246             $icon = $this->output->pix_icon(
247                 'i/empty',
248                 '',
249                 'moodle',
250                 array('class' => 'tree-icon'));
251             $icon = html_writer::span($icon, 'float-left');
252         }
253         $actions = \core_course\management\helper::get_category_listitem_actions($category);
254         $hasactions = !empty($actions) || $category->can_create_course();
256         $html = html_writer::start_tag('li', $attributes);
257         $html .= html_writer::start_div('clearfix');
258         $html .= html_writer::start_div('float-left ba-checkbox');
259         $html .= html_writer::empty_tag('input', $bcatinput).'&nbsp;';
260         $html .= html_writer::end_div();
261         $html .= $icon;
262         if ($hasactions) {
263             $textattributes = array('class' => 'float-left categoryname');
264         } else {
265             $textattributes = array('class' => 'float-left categoryname without-actions');
266         }
267         if (isset($textlabel)) {
268             $textattributes['aria-label'] = $textlabel;
269         }
270         $html .= html_writer::link($viewcaturl, $text, $textattributes);
271         $html .= html_writer::start_div('float-right');
272         if ($category->idnumber) {
273             $html .= html_writer::tag('span', s($category->idnumber), array('class' => 'dimmed idnumber'));
274         }
275         if ($hasactions) {
276             $html .= $this->category_listitem_actions($category, $actions);
277         }
278         $countid = 'course-count-'.$category->id;
279         $html .= html_writer::span(
280             html_writer::span($category->get_courses_count()) .
281             html_writer::span(get_string('courses'), 'accesshide', array('id' => $countid)) .
282             $courseicon,
283             'course-count dimmed',
284             array('aria-labelledby' => $countid)
285         );
286         $html .= html_writer::end_div();
287         $html .= html_writer::end_div();
288         if ($isexpanded) {
289             $html .= html_writer::start_tag('ul',
290                 array('class' => 'ml', 'role' => 'group', 'id' => 'subcategoryof'.$category->id));
291             $catatlevel = \core_course\management\helper::get_expanded_categories($category->path);
292             $catatlevel[] = array_shift($selectedcategories);
293             $catatlevel = array_unique($catatlevel);
294             foreach ($subcategories as $listitem) {
295                 $childcategories = (in_array($listitem->id, $catatlevel)) ? $listitem->get_children() : array();
296                 $html .= $this->category_listitem(
297                     $listitem,
298                     $childcategories,
299                     $listitem->get_children_count(),
300                     $selectedcategory,
301                     $selectedcategories
302                 );
303             }
304             $html .= html_writer::end_tag('ul');
305         }
306         $html .= html_writer::end_tag('li');
307         return $html;
308     }
310     /**
311      * Renderers the actions that are possible for the course category listing.
312      *
313      * These are not the actions associated with an individual category listing.
314      * That happens through category_listitem_actions.
315      *
316      * @param core_course_category $category
317      * @return string
318      */
319     public function category_listing_actions(core_course_category $category = null) {
320         $actions = array();
322         $cancreatecategory = $category && $category->can_create_subcategory();
323         $cancreatecategory = $cancreatecategory || core_course_category::can_create_top_level_category();
324         if ($category === null) {
325             $category = core_course_category::get(0);
326         }
328         if ($cancreatecategory) {
329             $url = new moodle_url('/course/editcategory.php', array('parent' => $category->id));
330             $actions[] = html_writer::link($url, get_string('createnewcategory'));
331         }
332         if (core_course_category::can_approve_course_requests()) {
333             $actions[] = html_writer::link(new moodle_url('/course/pending.php'), get_string('coursespending'));
334         }
335         if (count($actions) === 0) {
336             return '';
337         }
338         return html_writer::div(join(' | ', $actions), 'listing-actions category-listing-actions');
339     }
341     /**
342      * Renderers the actions for individual category list items.
343      *
344      * @param core_course_category $category
345      * @param array $actions
346      * @return string
347      */
348     public function category_listitem_actions(core_course_category $category, array $actions = null) {
349         if ($actions === null) {
350             $actions = \core_course\management\helper::get_category_listitem_actions($category);
351         }
352         $menu = new action_menu();
353         $menu->attributes['class'] .= ' category-item-actions item-actions';
354         $hasitems = false;
355         foreach ($actions as $key => $action) {
356             $hasitems = true;
357             $menu->add(new action_menu_link(
358                 $action['url'],
359                 $action['icon'],
360                 $action['string'],
361                 in_array($key, array('show', 'hide', 'moveup', 'movedown')),
362                 array('data-action' => $key, 'class' => 'action-'.$key)
363             ));
364         }
365         if (!$hasitems) {
366             return '';
367         }
368         return $this->render($menu);
369     }
371     public function render_action_menu($menu) {
372         global $OUTPUT;
374         return $OUTPUT->render($menu);
375     }
377     /**
378      * Renders bulk actions for categories.
379      *
380      * @param core_course_category $category The currently selected category if there is one.
381      * @return string
382      */
383     public function category_bulk_actions(core_course_category $category = null) {
384         // Resort courses.
385         // Change parent.
386         if (!core_course_category::can_resort_any() && !core_course_category::can_change_parent_any()) {
387             return '';
388         }
389         $strgo = new lang_string('go');
391         $html  = html_writer::start_div('category-bulk-actions bulk-actions');
392         $html .= html_writer::div(get_string('categorybulkaction'), 'accesshide', array('tabindex' => '0'));
393         if (core_course_category::can_resort_any()) {
394             $selectoptions = array(
395                 'selectedcategories' => get_string('selectedcategories'),
396                 'allcategories' => get_string('allcategories')
397             );
398             $form = html_writer::start_div();
399             if ($category) {
400                 $selectoptions = array('thiscategory' => get_string('thiscategory')) + $selectoptions;
401                 $form .= html_writer::empty_tag('input', array('type' => 'hidden', 'name' => 'currentcategoryid', 'value' => $category->id));
402             }
403             $form .= html_writer::div(
404                 html_writer::select(
405                     $selectoptions,
406                     'selectsortby',
407                     'selectedcategories',
408                     false,
409                     array('aria-label' => get_string('selectcategorysort'))
410                 )
411             );
412             $form .= html_writer::div(
413                 html_writer::select(
414                     array(
415                         'name' => get_string('sortbyx', 'moodle', get_string('categoryname')),
416                         'namedesc' => get_string('sortbyxreverse', 'moodle', get_string('categoryname')),
417                         'idnumber' => get_string('sortbyx', 'moodle', get_string('idnumbercoursecategory')),
418                         'idnumberdesc' => get_string('sortbyxreverse' , 'moodle' , get_string('idnumbercoursecategory')),
419                         'none' => get_string('dontsortcategories')
420                     ),
421                     'resortcategoriesby',
422                     'name',
423                     false,
424                     array('aria-label' => get_string('selectcategorysortby'), 'class' => 'm-t-1')
425                 )
426             );
427             $form .= html_writer::div(
428                 html_writer::select(
429                     array(
430                         'fullname' => get_string('sortbyx', 'moodle', get_string('fullnamecourse')),
431                         'fullnamedesc' => get_string('sortbyxreverse', 'moodle', get_string('fullnamecourse')),
432                         'shortname' => get_string('sortbyx', 'moodle', get_string('shortnamecourse')),
433                         'shortnamedesc' => get_string('sortbyxreverse', 'moodle', get_string('shortnamecourse')),
434                         'idnumber' => get_string('sortbyx', 'moodle', get_string('idnumbercourse')),
435                         'idnumberdesc' => get_string('sortbyxreverse', 'moodle', get_string('idnumbercourse')),
436                         'timecreated' => get_string('sortbyx', 'moodle', get_string('timecreatedcourse')),
437                         'timecreateddesc' => get_string('sortbyxreverse', 'moodle', get_string('timecreatedcourse')),
438                         'none' => get_string('dontsortcourses')
439                     ),
440                     'resortcoursesby',
441                     'fullname',
442                     false,
443                     array('aria-label' => get_string('selectcoursesortby'), 'class' => 'm-t-1')
444                 )
445             );
446             $form .= html_writer::empty_tag('input', array('type' => 'submit', 'name' => 'bulksort',
447                 'value' => get_string('sort'), 'class' => 'btn btn-secondary m-y-1'));
448             $form .= html_writer::end_div();
450             $html .= html_writer::start_div('detail-pair row yui3-g m-y-1');
451             $html .= html_writer::div(html_writer::span(get_string('sorting')), 'pair-key span3 col-md-3 yui3-u-1-4');
452             $html .= html_writer::div($form, 'pair-value span9 col-md-9 yui3-u-3-4');
453             $html .= html_writer::end_div();
454         }
455         if (core_course_category::can_change_parent_any()) {
456             $options = array();
457             if (has_capability('moodle/category:manage', context_system::instance())) {
458                 $options[0] = core_course_category::get(0)->get_formatted_name();
459             }
460             $options += core_course_category::make_categories_list('moodle/category:manage');
461             $select = html_writer::select(
462                 $options,
463                 'movecategoriesto',
464                 '',
465                 array('' => 'choosedots'),
466                 array('aria-labelledby' => 'moveselectedcategoriesto', 'class' => 'm-r-1')
467             );
468             $submit = array('type' => 'submit', 'name' => 'bulkmovecategories', 'value' => get_string('move'),
469                 'class' => 'btn btn-secondary');
470             $html .= $this->detail_pair(
471                 html_writer::span(get_string('moveselectedcategoriesto'), '', array('id' => 'moveselectedcategoriesto')),
472                 $select . html_writer::empty_tag('input', $submit)
473             );
474         }
475         $html .= html_writer::end_div();
476         return $html;
477     }
479     /**
480      * Renders a course listing.
481      *
482      * @param core_course_category $category The currently selected category. This is what the listing is focused on.
483      * @param core_course_list_element  $course The currently selected course.
484      * @param int $page The page being displayed.
485      * @param int $perpage The number of courses to display per page.
486      * @param string|null $viewmode The view mode the page is in, one out of 'default', 'combined', 'courses' or 'categories'.
487      * @return string
488      */
489     public function course_listing(core_course_category $category = null, core_course_list_element $course = null,
490                                    $page = 0, $perpage = 20,
491         $viewmode = 'default') {
493         if ($category === null) {
494             $html = html_writer::start_div('select-a-category');
495             $html .= html_writer::tag('h3', get_string('courses'),
496                 array('id' => 'course-listing-title', 'tabindex' => '0'));
497             $html .= $this->output->notification(get_string('selectacategory'), 'notifymessage');
498             $html .= html_writer::end_div();
499             return $html;
500         }
502         $page = max($page, 0);
503         $perpage = max($perpage, 2);
504         $totalcourses = $category->coursecount;
505         $totalpages = ceil($totalcourses / $perpage);
506         if ($page > $totalpages - 1) {
507             $page = $totalpages - 1;
508         }
509         $options = array(
510             'offset' => $page * $perpage,
511             'limit' => $perpage
512         );
513         $courseid = isset($course) ? $course->id : null;
514         $class = '';
515         if ($page === 0) {
516             $class .= ' firstpage';
517         }
518         if ($page + 1 === (int)$totalpages) {
519             $class .= ' lastpage';
520         }
522         $html  = html_writer::start_div('course-listing'.$class, array(
523             'data-category' => $category->id,
524             'data-page' => $page,
525             'data-totalpages' => $totalpages,
526             'data-totalcourses' => $totalcourses,
527             'data-canmoveoutof' => $category->can_move_courses_out_of() && $category->can_move_courses_into()
528         ));
529         $html .= html_writer::tag('h3', $category->get_formatted_name(),
530             array('id' => 'course-listing-title', 'tabindex' => '0'));
531         $html .= $this->course_listing_actions($category, $course, $perpage);
532         $html .= $this->listing_pagination($category, $page, $perpage, false, $viewmode);
533         $html .= html_writer::start_tag('ul', array('class' => 'ml course-list', 'role' => 'group'));
534         foreach ($category->get_courses($options) as $listitem) {
535             $html .= $this->course_listitem($category, $listitem, $courseid);
536         }
537         $html .= html_writer::end_tag('ul');
538         $html .= $this->listing_pagination($category, $page, $perpage, true, $viewmode);
539         $html .= $this->course_bulk_actions($category);
540         $html .= html_writer::end_div();
541         return $html;
542     }
544     /**
545      * Renders pagination for a course listing.
546      *
547      * @param core_course_category $category The category to produce pagination for.
548      * @param int $page The current page.
549      * @param int $perpage The number of courses to display per page.
550      * @param bool $showtotals Set to true to show the total number of courses and what is being displayed.
551      * @param string|null $viewmode The view mode the page is in, one out of 'default', 'combined', 'courses' or 'categories'.
552      * @return string
553      */
554     protected function listing_pagination(core_course_category $category, $page, $perpage, $showtotals = false,
555                                           $viewmode = 'default') {
556         $html = '';
557         $totalcourses = $category->get_courses_count();
558         $totalpages = ceil($totalcourses / $perpage);
559         if ($showtotals) {
560             if ($totalpages == 0) {
561                 $str = get_string('nocoursesyet');
562             } else if ($totalpages == 1) {
563                 $str = get_string('showingacourses', 'moodle', $totalcourses);
564             } else {
565                 $a = new stdClass;
566                 $a->start = ($page * $perpage) + 1;
567                 $a->end = min((($page + 1) * $perpage), $totalcourses);
568                 $a->total = $totalcourses;
569                 $str = get_string('showingxofycourses', 'moodle', $a);
570             }
571             $html .= html_writer::div($str, 'listing-pagination-totals dimmed');
572         }
574         if ($viewmode !== 'default') {
575             $baseurl = new moodle_url('/course/management.php', array('categoryid' => $category->id,
576                 'view' => $viewmode));
577         } else {
578             $baseurl = new moodle_url('/course/management.php', array('categoryid' => $category->id));
579         }
581         $html .= $this->output->paging_bar($totalcourses, $page, $perpage, $baseurl);
582         return $html;
583     }
585     /**
586      * Renderers a course list item.
587      *
588      * This function will be called for every course being displayed by course_listing.
589      *
590      * @param core_course_category $category The currently selected category and the category the course belongs to.
591      * @param core_course_list_element  $course The course to produce HTML for.
592      * @param int $selectedcourse The id of the currently selected course.
593      * @return string
594      */
595     public function course_listitem(core_course_category $category, core_course_list_element $course, $selectedcourse) {
597         $text = $course->get_formatted_name();
598         $attributes = array(
599             'class' => 'listitem listitem-course',
600             'data-id' => $course->id,
601             'data-selected' => ($selectedcourse == $course->id) ? '1' : '0',
602             'data-visible' => $course->visible ? '1' : '0'
603         );
605         $bulkcourseinput = array(
606             'type' => 'checkbox',
607             'name' => 'bc[]',
608             'value' => $course->id,
609             'class' => 'bulk-action-checkbox',
610             'aria-label' => get_string('bulkactionselect', 'moodle', $text),
611             'data-action' => 'select'
612         );
613         if (!$category->has_manage_capability()) {
614             // Very very hardcoded here.
615             $bulkcourseinput['style'] = 'visibility:hidden';
616         }
618         $viewcourseurl = new moodle_url($this->page->url, array('courseid' => $course->id));
620         $html  = html_writer::start_tag('li', $attributes);
621         $html .= html_writer::start_div('clearfix');
623         if ($category->can_resort_courses()) {
624             // In order for dnd to be available the user must be able to resort the category children..
625             $html .= html_writer::div($this->output->pix_icon('i/move_2d', get_string('dndcourse')), 'float-left drag-handle');
626         }
628         $html .= html_writer::start_div('ba-checkbox float-left');
629         $html .= html_writer::empty_tag('input', $bulkcourseinput).'&nbsp;';
630         $html .= html_writer::end_div();
631         $html .= html_writer::link($viewcourseurl, $text, array('class' => 'float-left coursename'));
632         $html .= html_writer::start_div('float-right');
633         if ($course->idnumber) {
634             $html .= html_writer::tag('span', s($course->idnumber), array('class' => 'dimmed idnumber'));
635         }
636         $html .= $this->course_listitem_actions($category, $course);
637         $html .= html_writer::end_div();
638         $html .= html_writer::end_div();
639         $html .= html_writer::end_tag('li');
640         return $html;
641     }
643     /**
644      * Renderers actions for the course listing.
645      *
646      * Not to be confused with course_listitem_actions which renderers the actions for individual courses.
647      *
648      * @param core_course_category $category
649      * @param core_course_list_element $course The currently selected course.
650      * @param int $perpage
651      * @return string
652      */
653     public function course_listing_actions(core_course_category $category, core_course_list_element $course = null, $perpage = 20) {
654         $actions = array();
655         if ($category->can_create_course()) {
656             $url = new moodle_url('/course/edit.php', array('category' => $category->id, 'returnto' => 'catmanage'));
657             $actions[] = html_writer::link($url, get_string('createnewcourse'));
658         }
659         if ($category->can_request_course()) {
660             // Request a new course.
661             $url = new moodle_url('/course/request.php', array('return' => 'management'));
662             $actions[] = html_writer::link($url, get_string('requestcourse'));
663         }
664         if ($category->can_resort_courses()) {
665             $params = $this->page->url->params();
666             $params['action'] = 'resortcourses';
667             $params['sesskey'] = sesskey();
668             $baseurl = new moodle_url('/course/management.php', $params);
669             $fullnameurl = new moodle_url($baseurl, array('resort' => 'fullname'));
670             $fullnameurldesc = new moodle_url($baseurl, array('resort' => 'fullnamedesc'));
671             $shortnameurl = new moodle_url($baseurl, array('resort' => 'shortname'));
672             $shortnameurldesc = new moodle_url($baseurl, array('resort' => 'shortnamedesc'));
673             $idnumberurl = new moodle_url($baseurl, array('resort' => 'idnumber'));
674             $idnumberdescurl = new moodle_url($baseurl, array('resort' => 'idnumberdesc'));
675             $timecreatedurl = new moodle_url($baseurl, array('resort' => 'timecreated'));
676             $timecreateddescurl = new moodle_url($baseurl, array('resort' => 'timecreateddesc'));
677             $menu = new action_menu(array(
678                 new action_menu_link_secondary($fullnameurl,
679                                                null,
680                                                get_string('sortbyx', 'moodle', get_string('fullnamecourse'))),
681                 new action_menu_link_secondary($fullnameurldesc,
682                                                null,
683                                                get_string('sortbyxreverse', 'moodle', get_string('fullnamecourse'))),
684                 new action_menu_link_secondary($shortnameurl,
685                                                null,
686                                                get_string('sortbyx', 'moodle', get_string('shortnamecourse'))),
687                 new action_menu_link_secondary($shortnameurldesc,
688                                                null,
689                                                get_string('sortbyxreverse', 'moodle', get_string('shortnamecourse'))),
690                 new action_menu_link_secondary($idnumberurl,
691                                                null,
692                                                get_string('sortbyx', 'moodle', get_string('idnumbercourse'))),
693                 new action_menu_link_secondary($idnumberdescurl,
694                                                null,
695                                                get_string('sortbyxreverse', 'moodle', get_string('idnumbercourse'))),
696                 new action_menu_link_secondary($timecreatedurl,
697                                                null,
698                                                get_string('sortbyx', 'moodle', get_string('timecreatedcourse'))),
699                 new action_menu_link_secondary($timecreateddescurl,
700                                                null,
701                                                get_string('sortbyxreverse', 'moodle', get_string('timecreatedcourse')))
702             ));
703             $menu->set_menu_trigger(get_string('resortcourses'));
704             $actions[] = $this->render($menu);
705         }
706         $strall = get_string('all');
707         $menu = new action_menu(array(
708             new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 5)), null, 5),
709             new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 10)), null, 10),
710             new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 20)), null, 20),
711             new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 50)), null, 50),
712             new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 100)), null, 100),
713             new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 999)), null, $strall),
714         ));
715         if ((int)$perpage === 999) {
716             $perpage = $strall;
717         }
718         $menu->attributes['class'] .= ' courses-per-page';
719         $menu->set_menu_trigger(get_string('perpagea', 'moodle', $perpage));
720         $actions[] = $this->render($menu);
721         return html_writer::div(join(' | ', $actions), 'listing-actions course-listing-actions');
722     }
724     /**
725      * Renderers actions for individual course actions.
726      *
727      * @param core_course_category $category The currently selected category.
728      * @param core_course_list_element  $course The course to renderer actions for.
729      * @return string
730      */
731     public function course_listitem_actions(core_course_category $category, core_course_list_element $course) {
732         $actions = \core_course\management\helper::get_course_listitem_actions($category, $course);
733         if (empty($actions)) {
734             return '';
735         }
736         $actionshtml = array();
737         foreach ($actions as $action) {
738             $action['attributes']['role'] = 'button';
739             $actionshtml[] = $this->output->action_icon($action['url'], $action['icon'], null, $action['attributes']);
740         }
741         return html_writer::span(join('', $actionshtml), 'course-item-actions item-actions');
742     }
744     /**
745      * Renderers bulk actions that can be performed on courses.
746      *
747      * @param core_course_category $category The currently selected category and the category in which courses that
748      *      are selectable belong.
749      * @return string
750      */
751     public function course_bulk_actions(core_course_category $category) {
752         $html  = html_writer::start_div('course-bulk-actions bulk-actions');
753         if ($category->can_move_courses_out_of()) {
754             $html .= html_writer::div(get_string('coursebulkaction'), 'accesshide', array('tabindex' => '0'));
755             $options = core_course_category::make_categories_list('moodle/category:manage');
756             $select = html_writer::select(
757                 $options,
758                 'movecoursesto',
759                 '',
760                 array('' => 'choosedots'),
761                 array('aria-labelledby' => 'moveselectedcoursesto', 'class' => 'm-r-1')
762             );
763             $submit = array('type' => 'submit', 'name' => 'bulkmovecourses', 'value' => get_string('move'),
764                 'class' => 'btn btn-secondary');
765             $html .= $this->detail_pair(
766                 html_writer::span(get_string('moveselectedcoursesto'), '', array('id' => 'moveselectedcoursesto')),
767                 $select . html_writer::empty_tag('input', $submit)
768             );
769         }
770         $html .= html_writer::end_div();
771         return $html;
772     }
774     /**
775      * Renderers bulk actions that can be performed on courses in search returns
776      *
777      * @return string
778      */
779     public function course_search_bulk_actions() {
780         $html  = html_writer::start_div('course-bulk-actions bulk-actions');
781         $html .= html_writer::div(get_string('coursebulkaction'), 'accesshide', array('tabindex' => '0'));
782         $options = core_course_category::make_categories_list('moodle/category:manage');
783         $select = html_writer::select(
784             $options,
785             'movecoursesto',
786             '',
787             array('' => 'choosedots'),
788             array('aria-labelledby' => 'moveselectedcoursesto')
789         );
790         $submit = array('type' => 'submit', 'name' => 'bulkmovecourses', 'value' => get_string('move'),
791             'class' => 'btn btn-secondary');
792         $html .= $this->detail_pair(
793             html_writer::span(get_string('moveselectedcoursesto'), '', array('id' => 'moveselectedcoursesto')),
794             $select . html_writer::empty_tag('input', $submit)
795         );
796         $html .= html_writer::end_div();
797         return $html;
798     }
800     /**
801      * Renderers detailed course information.
802      *
803      * @param core_course_list_element  $course The course to display details for.
804      * @return string
805      */
806     public function course_detail(core_course_list_element $course) {
807         $details = \core_course\management\helper::get_course_detail_array($course);
808         $fullname = $details['fullname']['value'];
810         $html  = html_writer::start_div('course-detail');
811         $html .= html_writer::tag('h3', $fullname, array('id' => 'course-detail-title', 'tabindex' => '0'));
812         $html .= $this->course_detail_actions($course);
813         foreach ($details as $class => $data) {
814             $html .= $this->detail_pair($data['key'], $data['value'], $class);
815         }
816         $html .= html_writer::end_div();
817         return $html;
818     }
820     /**
821      * Renderers a key value pair of information for display.
822      *
823      * @param string $key
824      * @param string $value
825      * @param string $class
826      * @return string
827      */
828     protected function detail_pair($key, $value, $class ='') {
829         $html = html_writer::start_div('detail-pair row yui3-g '.preg_replace('#[^a-zA-Z0-9_\-]#', '-', $class));
830         $html .= html_writer::div(html_writer::span($key), 'pair-key span3 col-md-3 yui3-u-1-4');
831         $html .= html_writer::div(html_writer::span($value), 'pair-value span9 col-md-9 m-b-1 yui3-u-3-4 form-inline');
832         $html .= html_writer::end_div();
833         return $html;
834     }
836     /**
837      * A collection of actions for a course.
838      *
839      * @param core_course_list_element  $course The course to display actions for.
840      * @return string
841      */
842     public function course_detail_actions(core_course_list_element $course) {
843         $actions = \core_course\management\helper::get_course_detail_actions($course);
844         if (empty($actions)) {
845             return '';
846         }
847         $options = array();
848         foreach ($actions as $action) {
849             $options[] = $this->action_link($action['url'], $action['string']);
850         }
851         return html_writer::div(join(' | ', $options), 'listing-actions course-detail-listing-actions');
852     }
854     /**
855      * Creates an action button (styled link)
856      *
857      * @param moodle_url $url The URL to go to when clicked.
858      * @param string $text The text for the button.
859      * @param string $id An id to give the button.
860      * @param string $class A class to give the button.
861      * @param array $attributes Any additional attributes
862      * @return string
863      */
864     protected function action_button(moodle_url $url, $text, $id = null, $class = null, $title = null, array $attributes = array()) {
865         if (isset($attributes['class'])) {
866             $attributes['class'] .= ' yui3-button';
867         } else {
868             $attributes['class'] = 'yui3-button';
869         }
870         if (!is_null($id)) {
871             $attributes['id'] = $id;
872         }
873         if (!is_null($class)) {
874             $attributes['class'] .= ' '.$class;
875         }
876         if (is_null($title)) {
877             $title = $text;
878         }
879         $attributes['title'] = $title;
880         if (!isset($attributes['role'])) {
881             $attributes['role'] = 'button';
882         }
883         return html_writer::link($url, $text, $attributes);
884     }
886     /**
887      * Opens a grid.
888      *
889      * Call {@link core_course_management_renderer::grid_column_start()} to create columns.
890      *
891      * @param string $id An id to give this grid.
892      * @param string $class A class to give this grid.
893      * @return string
894      */
895     public function grid_start($id = null, $class = null) {
896         $gridclass = 'grid-row-r row-fluid';
897         if (is_null($class)) {
898             $class = $gridclass;
899         } else {
900             $class .= ' ' . $gridclass;
901         }
902         $attributes = array();
903         if (!is_null($id)) {
904             $attributes['id'] = $id;
905         }
906         return html_writer::start_div($class, $attributes);
907     }
909     /**
910      * Closes the grid.
911      *
912      * @return string
913      */
914     public function grid_end() {
915         return html_writer::end_div();
916     }
918     /**
919      * Opens a grid column
920      *
921      * @param int $size The number of segments this column should span.
922      * @param string $id An id to give the column.
923      * @param string $class A class to give the column.
924      * @return string
925      */
926     public function grid_column_start($size, $id = null, $class = null) {
928         // Calculate Bootstrap grid sizing.
929         $bootstrapclass = 'span'.$size.' col-md-'.$size;
931         // Calculate YUI grid sizing.
932         if ($size === 12) {
933             $maxsize = 1;
934             $size = 1;
935         } else {
936             $maxsize = 12;
937             $divisors = array(8, 6, 5, 4, 3, 2);
938             foreach ($divisors as $divisor) {
939                 if (($maxsize % $divisor === 0) && ($size % $divisor === 0)) {
940                     $maxsize = $maxsize / $divisor;
941                     $size = $size / $divisor;
942                     break;
943                 }
944             }
945         }
946         if ($maxsize > 1) {
947             $yuigridclass =  "grid-col-{$size}-{$maxsize} grid-col";
948         } else {
949             $yuigridclass =  "grid-col-1 grid-col";
950         }
952         if (is_null($class)) {
953             $class = $yuigridclass . ' ' . $bootstrapclass;
954         } else {
955             $class .= ' ' . $yuigridclass . ' ' . $bootstrapclass;
956         }
957         $attributes = array();
958         if (!is_null($id)) {
959             $attributes['id'] = $id;
960         }
961         return html_writer::start_div($class, $attributes);
962     }
964     /**
965      * Closes a grid column.
966      *
967      * @return string
968      */
969     public function grid_column_end() {
970         return html_writer::end_div();
971     }
973     /**
974      * Renders an action_icon.
975      *
976      * This function uses the {@link core_renderer::action_link()} method for the
977      * most part. What it does different is prepare the icon as HTML and use it
978      * as the link text.
979      *
980      * @param string|moodle_url $url A string URL or moodel_url
981      * @param pix_icon $pixicon
982      * @param component_action $action
983      * @param array $attributes associative array of html link attributes + disabled
984      * @param bool $linktext show title next to image in link
985      * @return string HTML fragment
986      */
987     public function action_icon($url, pix_icon $pixicon, component_action $action = null,
988                                 array $attributes = null, $linktext = false) {
989         if (!($url instanceof moodle_url)) {
990             $url = new moodle_url($url);
991         }
992         $attributes = (array)$attributes;
994         if (empty($attributes['class'])) {
995             // Let devs override the class via $attributes.
996             $attributes['class'] = 'action-icon';
997         }
999         $icon = $this->render($pixicon);
1001         if ($linktext) {
1002             $text = $pixicon->attributes['alt'];
1003         } else {
1004             $text = '';
1005         }
1007         return $this->action_link($url, $icon.$text, $action, $attributes);
1008     }
1010     /**
1011      * Displays a view mode selector.
1012      *
1013      * @param array $modes An array of view modes.
1014      * @param string $currentmode The current view mode.
1015      * @param moodle_url $url The URL to use when changing actions. Defaults to the page URL.
1016      * @param string $param The param name.
1017      * @return string
1018      */
1019     public function view_mode_selector(array $modes, $currentmode, moodle_url $url = null, $param = 'view') {
1020         if ($url === null) {
1021             $url = $this->page->url;
1022         }
1024         $menu = new action_menu;
1025         $menu->attributes['class'] .= ' view-mode-selector vms ml-1';
1027         $selected = null;
1028         foreach ($modes as $mode => $modestr) {
1029             $attributes = array(
1030                 'class' => 'vms-mode',
1031                 'data-mode' => $mode
1032             );
1033             if ($currentmode === $mode) {
1034                 $attributes['class'] .= ' currentmode';
1035                 $selected = $modestr;
1036             }
1037             if ($selected === null) {
1038                 $selected = $modestr;
1039             }
1040             $modeurl = new moodle_url($url, array($param => $mode));
1041             if ($mode === 'default') {
1042                 $modeurl->remove_params($param);
1043             }
1044             $menu->add(new action_menu_link_secondary($modeurl, null, $modestr, $attributes));
1045         }
1047         $menu->set_menu_trigger($selected);
1049         $html = html_writer::start_div('view-mode-selector vms d-flex');
1050         $html .= get_string('viewing').' '.$this->render($menu);
1051         $html .= html_writer::end_div();
1053         return $html;
1054     }
1056     /**
1057      * Displays a search result listing.
1058      *
1059      * @param array $courses The courses to display.
1060      * @param int $totalcourses The total number of courses to display.
1061      * @param core_course_list_element  $course The currently selected course if there is one.
1062      * @param int $page The current page, starting at 0.
1063      * @param int $perpage The number of courses to display per page.
1064      * @param string $search The string we are searching for.
1065      * @return string
1066      */
1067     public function search_listing(array $courses, $totalcourses, core_course_list_element $course = null, $page = 0, $perpage = 20,
1068         $search = '') {
1069         $page = max($page, 0);
1070         $perpage = max($perpage, 2);
1071         $totalpages = ceil($totalcourses / $perpage);
1072         if ($page > $totalpages - 1) {
1073             $page = $totalpages - 1;
1074         }
1075         $courseid = isset($course) ? $course->id : null;
1076         $first = true;
1077         $last = false;
1078         $i = $page * $perpage;
1080         $html  = html_writer::start_div('course-listing', array(
1081             'data-category' => 'search',
1082             'data-page' => $page,
1083             'data-totalpages' => $totalpages,
1084             'data-totalcourses' => $totalcourses
1085         ));
1086         $html .= html_writer::tag('h3', get_string('courses'));
1087         $html .= $this->search_pagination($totalcourses, $page, $perpage);
1088         $html .= html_writer::start_tag('ul', array('class' => 'ml'));
1089         foreach ($courses as $listitem) {
1090             $i++;
1091             if ($i == $totalcourses) {
1092                 $last = true;
1093             }
1094             $html .= $this->search_listitem($listitem, $courseid, $first, $last);
1095             $first = false;
1096         }
1097         $html .= html_writer::end_tag('ul');
1098         $html .= $this->search_pagination($totalcourses, $page, $perpage, true, $search);
1099         $html .= $this->course_search_bulk_actions();
1100         $html .= html_writer::end_div();
1101         return $html;
1102     }
1104     /**
1105      * Displays pagination for search results.
1106      *
1107      * @param int $totalcourses The total number of courses to be displayed.
1108      * @param int $page The current page.
1109      * @param int $perpage The number of courses being displayed.
1110      * @param bool $showtotals Whether or not to print total information.
1111      * @param string $search The string we are searching for.
1112      * @return string
1113      */
1114     protected function search_pagination($totalcourses, $page, $perpage, $showtotals = false, $search = '') {
1115         $html = '';
1116         $totalpages = ceil($totalcourses / $perpage);
1117         if ($showtotals) {
1118             if ($totalpages == 0) {
1119                 $str = get_string('nocoursesfound', 'moodle', s($search));
1120             } else if ($totalpages == 1) {
1121                 $str = get_string('showingacourses', 'moodle', $totalcourses);
1122             } else {
1123                 $a = new stdClass;
1124                 $a->start = ($page * $perpage) + 1;
1125                 $a->end = min((($page + 1) * $perpage), $totalcourses);
1126                 $a->total = $totalcourses;
1127                 $str = get_string('showingxofycourses', 'moodle', $a);
1128             }
1129             $html .= html_writer::div($str, 'listing-pagination-totals dimmed');
1130         }
1132         if ($totalcourses < $perpage) {
1133             return $html;
1134         }
1135         $aside = 2;
1136         $span = $aside * 2 + 1;
1137         $start = max($page - $aside, 0);
1138         $end = min($page + $aside, $totalpages - 1);
1139         if (($end - $start) < $span) {
1140             if ($start == 0) {
1141                 $end = min($totalpages - 1, $span - 1);
1142             } else if ($end == ($totalpages - 1)) {
1143                 $start = max(0, $end - $span + 1);
1144             }
1145         }
1146         $items = array();
1147         $baseurl = $this->page->url;
1148         if ($page > 0) {
1149             $items[] = $this->action_button(new moodle_url($baseurl, array('page' => 0)), get_string('first'));
1150             $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $page - 1)), get_string('prev'));
1151             $items[] = '...';
1152         }
1153         for ($i = $start; $i <= $end; $i++) {
1154             $class = '';
1155             if ($page == $i) {
1156                 $class = 'active-page';
1157             }
1158             $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $i)), $i + 1, null, $class);
1159         }
1160         if ($page < ($totalpages - 1)) {
1161             $items[] = '...';
1162             $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $page + 1)), get_string('next'));
1163             $items[] = $this->action_button(new moodle_url($baseurl, array('page' => $totalpages - 1)), get_string('last'));
1164         }
1166         $html .= html_writer::div(join('', $items), 'listing-pagination');
1167         return $html;
1168     }
1170     /**
1171      * Renderers a search result course list item.
1172      *
1173      * This function will be called for every course being displayed by course_listing.
1174      *
1175      * @param core_course_list_element  $course The course to produce HTML for.
1176      * @param int $selectedcourse The id of the currently selected course.
1177      * @return string
1178      */
1179     public function search_listitem(core_course_list_element $course, $selectedcourse) {
1181         $text = $course->get_formatted_name();
1182         $attributes = array(
1183             'class' => 'listitem listitem-course',
1184             'data-id' => $course->id,
1185             'data-selected' => ($selectedcourse == $course->id) ? '1' : '0',
1186             'data-visible' => $course->visible ? '1' : '0'
1187         );
1188         $bulkcourseinput = '';
1189         if (core_course_category::get($course->category)->can_move_courses_out_of()) {
1190             $bulkcourseinput = array(
1191                 'type' => 'checkbox',
1192                 'name' => 'bc[]',
1193                 'value' => $course->id,
1194                 'class' => 'bulk-action-checkbox',
1195                 'aria-label' => get_string('bulkactionselect', 'moodle', $text),
1196                 'data-action' => 'select'
1197             );
1198         }
1199         $viewcourseurl = new moodle_url($this->page->url, array('courseid' => $course->id));
1200         $categoryname = core_course_category::get($course->category)->get_formatted_name();
1202         $html  = html_writer::start_tag('li', $attributes);
1203         $html .= html_writer::start_div('clearfix');
1204         $html .= html_writer::start_div('float-left');
1205         if ($bulkcourseinput) {
1206             $html .= html_writer::empty_tag('input', $bulkcourseinput).'&nbsp;';
1207         }
1208         $html .= html_writer::end_div();
1209         $html .= html_writer::link($viewcourseurl, $text, array('class' => 'float-left coursename'));
1210         $html .= html_writer::tag('span', $categoryname, array('class' => 'float-left categoryname'));
1211         $html .= html_writer::start_div('float-right');
1212         $html .= $this->search_listitem_actions($course);
1213         $html .= html_writer::tag('span', s($course->idnumber), array('class' => 'dimmed idnumber'));
1214         $html .= html_writer::end_div();
1215         $html .= html_writer::end_div();
1216         $html .= html_writer::end_tag('li');
1217         return $html;
1218     }
1220     /**
1221      * Renderers actions for individual course actions.
1222      *
1223      * @param core_course_list_element  $course The course to renderer actions for.
1224      * @return string
1225      */
1226     public function search_listitem_actions(core_course_list_element $course) {
1227         $baseurl = new moodle_url(
1228             '/course/managementsearch.php',
1229             array('courseid' => $course->id, 'categoryid' => $course->category, 'sesskey' => sesskey())
1230         );
1231         $actions = array();
1232         // Edit.
1233         if ($course->can_access()) {
1234             if ($course->can_edit()) {
1235                 $actions[] = $this->output->action_icon(
1236                     new moodle_url('/course/edit.php', array('id' => $course->id)),
1237                     new pix_icon('t/edit', get_string('edit')),
1238                     null,
1239                     array('class' => 'action-edit')
1240                 );
1241             }
1242             // Delete.
1243             if ($course->can_delete()) {
1244                 $actions[] = $this->output->action_icon(
1245                     new moodle_url('/course/delete.php', array('id' => $course->id)),
1246                     new pix_icon('t/delete', get_string('delete')),
1247                     null,
1248                     array('class' => 'action-delete')
1249                 );
1250             }
1251             // Show/Hide.
1252             if ($course->can_change_visibility()) {
1253                     $actions[] = $this->output->action_icon(
1254                         new moodle_url($baseurl, array('action' => 'hidecourse')),
1255                         new pix_icon('t/hide', get_string('hide')),
1256                         null,
1257                         array('data-action' => 'hide', 'class' => 'action-hide')
1258                     );
1259                     $actions[] = $this->output->action_icon(
1260                         new moodle_url($baseurl, array('action' => 'showcourse')),
1261                         new pix_icon('t/show', get_string('show')),
1262                         null,
1263                         array('data-action' => 'show', 'class' => 'action-show')
1264                     );
1265             }
1266         }
1267         if (empty($actions)) {
1268             return '';
1269         }
1270         return html_writer::span(join('', $actions), 'course-item-actions item-actions');
1271     }
1273     /**
1274      * Renders html to display a course search form
1275      *
1276      * @param string $value default value to populate the search field
1277      * @param string $format display format - 'plain' (default), 'short' or 'navbar'
1278      * @return string
1279      */
1280     public function course_search_form($value = '', $format = 'plain') {
1281         static $count = 0;
1282         $formid = 'coursesearch';
1283         if ((++$count) > 1) {
1284             $formid .= $count;
1285         }
1287         switch ($format) {
1288             case 'navbar' :
1289                 $formid = 'coursesearchnavbar';
1290                 $inputid = 'navsearchbox';
1291                 $inputsize = 20;
1292                 break;
1293             case 'short' :
1294                 $inputid = 'shortsearchbox';
1295                 $inputsize = 12;
1296                 break;
1297             default :
1298                 $inputid = 'coursesearchbox';
1299                 $inputsize = 30;
1300         }
1302         $strsearchcourses = get_string("searchcourses");
1303         $searchurl = new moodle_url('/course/management.php');
1305         $output = html_writer::start_tag('form', array('id' => $formid, 'action' => $searchurl, 'method' => 'get',
1306             'class' => 'form-inline'));
1307         $output .= html_writer::start_tag('fieldset', array('class' => 'coursesearchbox invisiblefieldset m-y-1'));
1308         $output .= html_writer::tag('label', $strsearchcourses, array('for' => $inputid));
1309         $output .= html_writer::empty_tag('input', array('type' => 'text', 'id' => $inputid, 'size' => $inputsize,
1310             'name' => 'search', 'value' => s($value), 'class' => 'form-control m-x-1'));
1311         $output .= html_writer::empty_tag('input', array('type' => 'submit', 'value' => get_string('go'),
1312             'class' => 'btn btn-secondary'));
1313         $output .= html_writer::end_tag('fieldset');
1314         $output .= html_writer::end_tag('form');
1316         return $output;
1317     }
1319     /**
1320      * Creates access hidden skip to links for the displayed sections.
1321      *
1322      * @param bool $displaycategorylisting
1323      * @param bool $displaycourselisting
1324      * @param bool $displaycoursedetail
1325      * @return string
1326      */
1327     public function accessible_skipto_links($displaycategorylisting, $displaycourselisting, $displaycoursedetail) {
1328         $html = html_writer::start_div('skiplinks accesshide');
1329         $url = new moodle_url($this->page->url);
1330         if ($displaycategorylisting) {
1331             $url->set_anchor('category-listing');
1332             $html .= html_writer::link($url, get_string('skiptocategorylisting'), array('class' => 'skip'));
1333         }
1334         if ($displaycourselisting) {
1335             $url->set_anchor('course-listing');
1336             $html .= html_writer::link($url, get_string('skiptocourselisting'), array('class' => 'skip'));
1337         }
1338         if ($displaycoursedetail) {
1339             $url->set_anchor('course-detail');
1340             $html .= html_writer::link($url, get_string('skiptocoursedetails'), array('class' => 'skip'));
1341         }
1342         $html .= html_writer::end_div();
1343         return $html;
1344     }