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