MDL-62656 course: Align elements in course and category management
[moodle.git] / theme / boost / classes / output / core_course / management / renderer.php
CommitLineData
3ec69c2e
BB
1<?php
2// This file is part of The Bootstrap Moodle theme
3//
4// Moodle is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
8//
9// Moodle is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
13//
14// You should have received a copy of the GNU General Public License
15// along with Moodle. If not, see <http://www.gnu.org/licenses/>.
16
17/**
18 * Renderers to align Moodle's HTML with that expected by Bootstrap
19 *
20 * @package theme_boost
21 * @copyright 2018 Bas Brands
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 */
24
25namespace theme_boost\output\core_course\management;
26defined('MOODLE_INTERNAL') || die();
27
28require_once($CFG->dirroot . "/course/classes/management_renderer.php");
29
30use html_writer;
31use coursecat;
32use moodle_url;
33use course_in_list;
34use lang_string;
35use context_system;
36use stdClass;
37use action_menu;
38use action_menu_link_secondary;
39
40/**
41 * Main renderer for the course management pages.
42 *
43 * @package theme_boost
44 * @copyright 2013 Sam Hemelryk
45 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
46 */
47class renderer extends \core_course_management_renderer {
48
49 /**
50 * Opens a grid.
51 *
52 * Call {@link core_course_management_renderer::grid_column_start()} to create columns.
53 *
54 * @param string $id An id to give this grid.
55 * @param string $class A class to give this grid.
56 * @return string
57 */
58 public function grid_start($id = null, $class = null) {
59 $gridclass = 'grid-start grid-row-r d-flex flex-wrap row';
60 if (is_null($class)) {
61 $class = $gridclass;
62 } else {
63 $class .= ' ' . $gridclass;
64 }
65 $attributes = array();
66 if (!is_null($id)) {
67 $attributes['id'] = $id;
68 }
69 return html_writer::start_div($class, $attributes);
70 }
71
72 /**
73 * Opens a grid column
74 *
75 * @param int $size The number of segments this column should span.
76 * @param string $id An id to give the column.
77 * @param string $class A class to give the column.
78 * @return string
79 */
80 public function grid_column_start($size, $id = null, $class = null) {
81
82 if ($id == 'course-detail') {
83 $size = 12;
84 $bootstrapclass = 'col-md-'.$size;
85 } else {
86 $bootstrapclass = 'd-flex flex-wrap px-3 mb-3';
87 }
88
89 $yuigridclass = "col-sm";
90
91 if (is_null($class)) {
92 $class = $yuigridclass . ' ' . $bootstrapclass;
93 } else {
94 $class .= ' ' . $yuigridclass . ' ' . $bootstrapclass;
95 }
96 $attributes = array();
97 if (!is_null($id)) {
98 $attributes['id'] = $id;
99 }
100 return html_writer::start_div($class . " grid_column_start", $attributes);
101 }
102
103 /**
104 * Renderers detailed course information.
105 *
106 * @param course_in_list $course The course to display details for.
107 * @return string
108 */
109 public function course_detail(course_in_list $course) {
110 $details = \core_course\management\helper::get_course_detail_array($course);
111 $fullname = $details['fullname']['value'];
112
113 $html = html_writer::start_div('course-detail card');
114 $html .= html_writer::start_div('card-header');
115 $html .= html_writer::tag('h3', $fullname, array('id' => 'course-detail-title',
116 'class' => 'card-title', 'tabindex' => '0'));
117 $html .= html_writer::end_div();
118 $html .= html_writer::start_div('card-body');
119 $html .= $this->course_detail_actions($course);
120 foreach ($details as $class => $data) {
121 $html .= $this->detail_pair($data['key'], $data['value'], $class);
122 }
123 $html .= html_writer::end_div();
124 $html .= html_writer::end_div();
125 return $html;
126 }
127
128 /**
129 * Renders html to display a course search form
130 *
131 * @param string $value default value to populate the search field
132 * @param string $format display format - 'plain' (default), 'short' or 'navbar'
133 * @return string
134 */
135 public function course_search_form($value = '', $format = 'plain') {
136 static $count = 0;
137 $formid = 'coursesearch';
138 if ((++$count) > 1) {
139 $formid .= $count;
140 }
141
142 switch ($format) {
143 case 'navbar' :
144 $formid = 'coursesearchnavbar';
145 $inputid = 'navsearchbox';
146 $inputsize = 20;
147 break;
148 case 'short' :
149 $inputid = 'shortsearchbox';
150 $inputsize = 12;
151 break;
152 default :
153 $inputid = 'coursesearchbox';
154 $inputsize = 30;
155 }
156
157 $strsearchcourses = get_string("searchcourses");
158 $searchurl = new moodle_url('/course/management.php');
159
160 $output = html_writer::start_div('row');
161 $output .= html_writer::start_div('col-md-12');
162 $output .= html_writer::start_tag('form', array('class' => 'card', 'id' => $formid,
163 'action' => $searchurl, 'method' => 'get'));
164 $output .= html_writer::start_tag('fieldset', array('class' => 'coursesearchbox invisiblefieldset'));
165 $output .= html_writer::tag('div', $this->output->heading($strsearchcourses.': ', 2, 'm-0'),
166 array('class' => 'card-header'));
167 $output .= html_writer::start_div('card-body');
168 $output .= html_writer::start_div('input-group col-sm-6 col-lg-4 m-auto');
169 $output .= html_writer::empty_tag('input', array('class' => 'form-control', 'type' => 'text', 'id' => $inputid,
170 'size' => $inputsize, 'name' => 'search', 'value' => s($value)));
171 $output .= html_writer::start_tag('span', array('class' => 'input-group-btn'));
172 $output .= html_writer::tag('button', get_string('go'), array('class' => 'btn btn-primary', 'type' => 'submit'));
173 $output .= html_writer::end_tag('span');
174 $output .= html_writer::end_div();
175 $output .= html_writer::end_div();
176 $output .= html_writer::end_tag('fieldset');
177 $output .= html_writer::end_tag('form');
178 $output .= html_writer::end_div();
179 $output .= html_writer::end_div();
180
181 return $output;
182 }
183
184 /**
185 * Presents a course category listing.
186 *
187 * @param coursecat $category The currently selected category. Also the category to highlight in the listing.
188 * @return string
189 */
190 public function category_listing(coursecat $category = null) {
191
192 if ($category === null) {
193 $selectedparents = array();
194 $selectedcategory = null;
195 } else {
196 $selectedparents = $category->get_parents();
197 $selectedparents[] = $category->id;
198 $selectedcategory = $category->id;
199 }
200 $catatlevel = \core_course\management\helper::get_expanded_categories('');
201 $catatlevel[] = array_shift($selectedparents);
202 $catatlevel = array_unique($catatlevel);
203
204 $listing = coursecat::get(0)->get_children();
205
206 $attributes = array(
207 'class' => 'ml-1 list-unstyled',
208 'role' => 'tree',
209 'aria-labelledby' => 'category-listing-title'
210 );
211
212 $html = html_writer::start_div('category-listing card w-100');
213 $html .= html_writer::tag('h3', get_string('categories'),
214 array('class' => 'card-header', 'id' => 'category-listing-title'));
215 $html .= html_writer::start_div('card-body');
216 $html .= $this->category_listing_actions($category);
217 $html .= html_writer::start_tag('ul', $attributes);
218 foreach ($listing as $listitem) {
219 // Render each category in the listing.
220 $subcategories = array();
221 if (in_array($listitem->id, $catatlevel)) {
222 $subcategories = $listitem->get_children();
223 }
224 $html .= $this->category_listitem(
225 $listitem,
226 $subcategories,
227 $listitem->get_children_count(),
228 $selectedcategory,
229 $selectedparents
230 );
231 }
232 $html .= html_writer::end_tag('ul');
233 $html .= $this->category_bulk_actions($category);
234 $html .= html_writer::end_div();
235 $html .= html_writer::end_div();
236 return $html;
237 }
238
239 /**
240 * Renders a category list item.
241 *
242 * This function gets called recursively to render sub categories.
243 *
244 * @param coursecat $category The category to render as listitem.
245 * @param coursecat[] $subcategories The subcategories belonging to the category being rented.
246 * @param int $totalsubcategories The total number of sub categories.
247 * @param int $selectedcategory The currently selected category
248 * @param int[] $selectedcategories The path to the selected category and its ID.
249 * @return string
250 */
251 public function category_listitem(coursecat $category, array $subcategories, $totalsubcategories,
252 $selectedcategory = null, $selectedcategories = array()) {
253
254 $isexpandable = ($totalsubcategories > 0);
255 $isexpanded = (!empty($subcategories));
256 $activecategory = ($selectedcategory === $category->id);
257 $attributes = array(
258 'class' => 'listitem listitem-category list-group-item list-group-item-action',
259 'data-id' => $category->id,
260 'data-expandable' => $isexpandable ? '1' : '0',
261 'data-expanded' => $isexpanded ? '1' : '0',
262 'data-selected' => $activecategory ? '1' : '0',
263 'data-visible' => $category->visible ? '1' : '0',
264 'role' => 'treeitem',
265 'aria-expanded' => $isexpanded ? 'true' : 'false'
266 );
267 $text = $category->get_formatted_name();
268 if ($category->parent) {
269 $a = new stdClass;
270 $a->category = $text;
271 $a->parentcategory = $category->get_parent_coursecat()->get_formatted_name();
272 $textlabel = get_string('categorysubcategoryof', 'moodle', $a);
273 }
274 $courseicon = $this->output->pix_icon('i/course', get_string('courses'));
275 $bcatinput = array(
276 'type' => 'checkbox',
277 'name' => 'bcat[]',
278 'value' => $category->id,
279 'class' => 'bulk-action-checkbox',
280 'aria-label' => get_string('bulkactionselect', 'moodle', $text),
281 'data-action' => 'select'
282 );
283
284 if (!$category->can_resort_subcategories() && !$category->has_manage_capability()) {
285 // Very very hardcoded here.
286 $bcatinput['style'] = 'visibility:hidden';
287 }
288
289 $viewcaturl = new moodle_url('/course/management.php', array('categoryid' => $category->id));
290 if ($isexpanded) {
291 $icon = $this->output->pix_icon('t/switch_minus', get_string('collapse'),
292 'moodle', array('class' => 'tree-icon', 'title' => ''));
293 $icon = html_writer::link(
294 $viewcaturl,
295 $icon,
296 array(
297 'class' => 'float-left',
298 'data-action' => 'collapse',
299 'title' => get_string('collapsecategory', 'moodle', $text),
300 'aria-controls' => 'subcategoryof'.$category->id
301 )
302 );
303 } else if ($isexpandable) {
304 $icon = $this->output->pix_icon('t/switch_plus', get_string('expand'),
305 'moodle', array('class' => 'tree-icon', 'title' => ''));
306 $icon = html_writer::link(
307 $viewcaturl,
308 $icon,
309 array(
310 'class' => 'float-left',
311 'data-action' => 'expand',
312 'title' => get_string('expandcategory', 'moodle', $text)
313 )
314 );
315 } else {
316 $icon = $this->output->pix_icon(
04b1bea1 317 'i/empty',
3ec69c2e
BB
318 '',
319 'moodle',
320 array('class' => 'tree-icon', 'title' => get_string('showcategory', 'moodle', $text))
321 );
322 $icon = html_writer::span($icon, 'float-left');
323 }
324 $actions = \core_course\management\helper::get_category_listitem_actions($category);
325 $hasactions = !empty($actions) || $category->can_create_course();
326
327 $html = html_writer::start_tag('li', $attributes);
328 $html .= html_writer::start_div('clearfix');
329 $html .= html_writer::start_div('float-left ba-checkbox');
330 $html .= html_writer::empty_tag('input', $bcatinput).'&nbsp;';
331 $html .= html_writer::end_div();
332 $html .= $icon;
333 if ($hasactions) {
334 $textattributes = array('class' => 'float-left categoryname');
335 } else {
336 $textattributes = array('class' => 'float-left categoryname without-actions');
337 }
338 if (isset($textlabel)) {
339 $textattributes['aria-label'] = $textlabel;
340 }
341 $html .= html_writer::link($viewcaturl, $text, $textattributes);
342 $html .= html_writer::start_div('float-right d-flex');
343 if ($category->idnumber) {
344 $html .= html_writer::tag('span', s($category->idnumber), array('class' => 'dimmed idnumber'));
345 }
346 if ($hasactions) {
347 $html .= $this->category_listitem_actions($category, $actions);
348 }
349 $countid = 'course-count-'.$category->id;
350 $html .= html_writer::span(
351 html_writer::span($category->get_courses_count()) .
352 html_writer::span(get_string('courses'), 'accesshide', array('id' => $countid)) .
353 $courseicon,
354 'course-count dimmed',
355 array('aria-labelledby' => $countid)
356 );
357 $html .= html_writer::end_div();
358 $html .= html_writer::end_div();
359 if ($isexpanded) {
360 $html .= html_writer::start_tag('ul',
361 array('class' => 'ml', 'role' => 'group', 'id' => 'subcategoryof'.$category->id));
362 $catatlevel = \core_course\management\helper::get_expanded_categories($category->path);
363 $catatlevel[] = array_shift($selectedcategories);
364 $catatlevel = array_unique($catatlevel);
365 foreach ($subcategories as $listitem) {
366 $childcategories = (in_array($listitem->id, $catatlevel)) ? $listitem->get_children() : array();
367 $html .= $this->category_listitem(
368 $listitem,
369 $childcategories,
370 $listitem->get_children_count(),
371 $selectedcategory,
372 $selectedcategories
373 );
374 }
375 $html .= html_writer::end_tag('ul');
376 }
377 $html .= html_writer::end_tag('li');
378 return $html;
379 }
380
381 /**
382 * Renderers the actions that are possible for the course category listing.
383 *
384 * These are not the actions associated with an individual category listing.
385 * That happens through category_listitem_actions.
386 *
387 * @param coursecat $category
388 * @return string
389 */
390 public function category_listing_actions(coursecat $category = null) {
391 $actions = array();
392
393 $cancreatecategory = $category && $category->can_create_subcategory();
394 $cancreatecategory = $cancreatecategory || coursecat::can_create_top_level_category();
395 if ($category === null) {
396 $category = coursecat::get(0);
397 }
398
399 if ($cancreatecategory) {
400 $url = new moodle_url('/course/editcategory.php', array('parent' => $category->id));
401 $actions[] = html_writer::link($url, get_string('createnewcategory'), array('class' => 'btn btn-default'));
402 }
403 if (coursecat::can_approve_course_requests()) {
404 $actions[] = html_writer::link(new moodle_url('/course/pending.php'), get_string('coursespending'));
405 }
406 if (count($actions) === 0) {
407 return '';
408 }
409 return html_writer::div(join(' ', $actions), 'listing-actions category-listing-actions mb-3');
410 }
411
412 /**
413 * Renders a course listing.
414 *
415 * @param coursecat $category The currently selected category. This is what the listing is focused on.
416 * @param course_in_list $course The currently selected course.
417 * @param int $page The page being displayed.
418 * @param int $perpage The number of courses to display per page.
d29bde59 419 * @param string|null $viewmode The view mode the page is in, one out of 'default', 'combined', 'courses' or 'categories'.
3ec69c2e
BB
420 * @return string
421 */
d29bde59
LB
422 public function course_listing(coursecat $category = null, course_in_list $course = null,
423 $page = 0, $perpage = 20, $viewmode = 'default') {
3ec69c2e
BB
424
425 if ($category === null) {
426 $html = html_writer::start_div('select-a-category');
427 $html .= html_writer::tag('h3', get_string('courses'),
428 array('id' => 'course-listing-title', 'tabindex' => '0'));
429 $html .= $this->output->notification(get_string('selectacategory'), 'notifymessage');
430 $html .= html_writer::end_div();
431 return $html;
432 }
433
434 $page = max($page, 0);
435 $perpage = max($perpage, 2);
436 $totalcourses = $category->coursecount;
437 $totalpages = ceil($totalcourses / $perpage);
438 if ($page > $totalpages - 1) {
439 $page = $totalpages - 1;
440 }
441 $options = array(
442 'offset' => $page * $perpage,
443 'limit' => $perpage
444 );
445 $courseid = isset($course) ? $course->id : null;
446 $class = '';
447 if ($page === 0) {
448 $class .= ' firstpage';
449 }
450 if ($page + 1 === (int)$totalpages) {
451 $class .= ' lastpage';
452 }
453
454 $html = html_writer::start_div('card course-listing w-100'.$class, array(
455 'data-category' => $category->id,
456 'data-page' => $page,
457 'data-totalpages' => $totalpages,
458 'data-totalcourses' => $totalcourses,
459 'data-canmoveoutof' => $category->can_move_courses_out_of() && $category->can_move_courses_into()
460 ));
461 $html .= html_writer::tag('h3', $category->get_formatted_name(),
462 array('id' => 'course-listing-title', 'tabindex' => '0', 'class' => 'card-header'));
463 $html .= html_writer::start_div('card-body');
464 $html .= $this->course_listing_actions($category, $course, $perpage);
d29bde59 465 $html .= $this->listing_pagination($category, $page, $perpage, false, $viewmode);
1801b905 466 $html .= html_writer::start_tag('ul', array('class' => 'ml course-list', 'role' => 'group'));
3ec69c2e
BB
467 foreach ($category->get_courses($options) as $listitem) {
468 $html .= $this->course_listitem($category, $listitem, $courseid);
469 }
470 $html .= html_writer::end_tag('ul');
d29bde59 471 $html .= $this->listing_pagination($category, $page, $perpage, true, $viewmode);
3ec69c2e
BB
472 $html .= $this->course_bulk_actions($category);
473 $html .= html_writer::end_div();
474 $html .= html_writer::end_div();
475 return $html;
476 }
477
478 /**
479 * Renderers a course list item.
480 *
481 * This function will be called for every course being displayed by course_listing.
482 *
483 * @param coursecat $category The currently selected category and the category the course belongs to.
484 * @param course_in_list $course The course to produce HTML for.
485 * @param int $selectedcourse The id of the currently selected course.
486 * @return string
487 */
488 public function course_listitem(coursecat $category, course_in_list $course, $selectedcourse) {
489
490 $text = $course->get_formatted_name();
491 $attributes = array(
492 'class' => 'listitem listitem-course list-group-item list-group-item-action',
493 'data-id' => $course->id,
494 'data-selected' => ($selectedcourse == $course->id) ? '1' : '0',
495 'data-visible' => $course->visible ? '1' : '0'
496 );
497
498 $bulkcourseinput = array(
499 'type' => 'checkbox',
500 'name' => 'bc[]',
501 'value' => $course->id,
502 'class' => 'bulk-action-checkbox',
503 'aria-label' => get_string('bulkactionselect', 'moodle', $text),
504 'data-action' => 'select'
505 );
506 if (!$category->has_manage_capability()) {
507 // Very very hardcoded here.
508 $bulkcourseinput['style'] = 'visibility:hidden';
509 }
510
511 $viewcourseurl = new moodle_url($this->page->url, array('courseid' => $course->id));
512
513 $html = html_writer::start_tag('li', $attributes);
514 $html .= html_writer::start_div('clearfix');
515
516 if ($category->can_resort_courses()) {
517 // In order for dnd to be available the user must be able to resort the category children..
518 $html .= html_writer::div($this->output->pix_icon('i/move_2d', get_string('dndcourse')), 'float-left drag-handle');
519 }
520
521 $html .= html_writer::start_div('ba-checkbox float-left');
522 $html .= html_writer::empty_tag('input', $bulkcourseinput).'&nbsp;';
523 $html .= html_writer::end_div();
524 $html .= html_writer::link($viewcourseurl, $text, array('class' => 'float-left coursename'));
525 $html .= html_writer::start_div('float-right');
526 if ($course->idnumber) {
527 $html .= html_writer::tag('span', s($course->idnumber), array('class' => 'dimmed idnumber'));
528 }
529 $html .= $this->course_listitem_actions($category, $course);
530 $html .= html_writer::end_div();
531 $html .= html_writer::end_div();
532 $html .= html_writer::end_tag('li');
533 return $html;
534 }
535
536 /**
537 * Renderers actions for the course listing.
538 *
539 * Not to be confused with course_listitem_actions which renderers the actions for individual courses.
540 *
541 * @param coursecat $category
542 * @param course_in_list $course The currently selected course.
543 * @param int $perpage
544 * @return string
545 */
546 public function course_listing_actions(coursecat $category, course_in_list $course = null, $perpage = 20) {
547 $actions = array();
548 if ($category->can_create_course()) {
549 $url = new moodle_url('/course/edit.php', array('category' => $category->id, 'returnto' => 'catmanage'));
550 $actions[] = html_writer::link($url, get_string('createnewcourse'), array('class' => 'btn btn-default'));
551 }
552 if ($category->can_request_course()) {
553 // Request a new course.
554 $url = new moodle_url('/course/request.php', array('return' => 'management'));
555 $actions[] = html_writer::link($url, get_string('requestcourse'));
556 }
557 if ($category->can_resort_courses()) {
558 $params = $this->page->url->params();
559 $params['action'] = 'resortcourses';
560 $params['sesskey'] = sesskey();
561 $baseurl = new moodle_url('/course/management.php', $params);
562 $fullnameurl = new moodle_url($baseurl, array('resort' => 'fullname'));
563 $fullnameurldesc = new moodle_url($baseurl, array('resort' => 'fullnamedesc'));
564 $shortnameurl = new moodle_url($baseurl, array('resort' => 'shortname'));
565 $shortnameurldesc = new moodle_url($baseurl, array('resort' => 'shortnamedesc'));
566 $idnumberurl = new moodle_url($baseurl, array('resort' => 'idnumber'));
567 $idnumberdescurl = new moodle_url($baseurl, array('resort' => 'idnumberdesc'));
568 $timecreatedurl = new moodle_url($baseurl, array('resort' => 'timecreated'));
569 $timecreateddescurl = new moodle_url($baseurl, array('resort' => 'timecreateddesc'));
570 $menu = new action_menu(array(
571 new action_menu_link_secondary($fullnameurl,
572 null,
573 get_string('sortbyx', 'moodle', get_string('fullnamecourse'))),
574 new action_menu_link_secondary($fullnameurldesc,
575 null,
576 get_string('sortbyxreverse', 'moodle', get_string('fullnamecourse'))),
577 new action_menu_link_secondary($shortnameurl,
578 null,
579 get_string('sortbyx', 'moodle', get_string('shortnamecourse'))),
580 new action_menu_link_secondary($shortnameurldesc,
581 null,
582 get_string('sortbyxreverse', 'moodle', get_string('shortnamecourse'))),
583 new action_menu_link_secondary($idnumberurl,
584 null,
585 get_string('sortbyx', 'moodle', get_string('idnumbercourse'))),
586 new action_menu_link_secondary($idnumberdescurl,
587 null,
588 get_string('sortbyxreverse', 'moodle', get_string('idnumbercourse'))),
589 new action_menu_link_secondary($timecreatedurl,
590 null,
591 get_string('sortbyx', 'moodle', get_string('timecreatedcourse'))),
592 new action_menu_link_secondary($timecreateddescurl,
593 null,
594 get_string('sortbyxreverse', 'moodle', get_string('timecreatedcourse')))
595 ));
596 $menu->set_menu_trigger(get_string('resortcourses'));
597 $actions[] = $this->render($menu);
598 }
599 $strall = get_string('all');
600 $menu = new action_menu(array(
601 new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 5)), null, 5),
602 new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 10)), null, 10),
603 new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 20)), null, 20),
604 new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 50)), null, 50),
605 new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 100)), null, 100),
606 new action_menu_link_secondary(new moodle_url($this->page->url, array('perpage' => 999)), null, $strall),
607 ));
608 if ((int)$perpage === 999) {
609 $perpage = $strall;
610 }
611 $menu->attributes['class'] .= ' courses-per-page';
612 $menu->set_menu_trigger(get_string('perpagea', 'moodle', $perpage));
613 $actions[] = $this->render($menu);
614 return html_writer::div(join(' ', $actions), 'listing-actions course-listing-actions');
615 }
616
617 /**
618 * Displays a search result listing.
619 *
620 * @param array $courses The courses to display.
621 * @param int $totalcourses The total number of courses to display.
622 * @param course_in_list $course The currently selected course if there is one.
623 * @param int $page The current page, starting at 0.
624 * @param int $perpage The number of courses to display per page.
625 * @param string $search The string we are searching for.
626 * @return string
627 */
628 public function search_listing(array $courses, $totalcourses, course_in_list $course = null, $page = 0, $perpage = 20,
629 $search = '') {
630 $page = max($page, 0);
631 $perpage = max($perpage, 2);
632 $totalpages = ceil($totalcourses / $perpage);
633 if ($page > $totalpages - 1) {
634 $page = $totalpages - 1;
635 }
636 $courseid = isset($course) ? $course->id : null;
637 $first = true;
638 $last = false;
639 $i = $page * $perpage;
640
641 $html = html_writer::start_div('course-listing w-100', array(
642 'data-category' => 'search',
643 'data-page' => $page,
644 'data-totalpages' => $totalpages,
645 'data-totalcourses' => $totalcourses
646 ));
647 $html .= html_writer::tag('h3', get_string('courses'));
648 $html .= $this->search_pagination($totalcourses, $page, $perpage);
649 $html .= html_writer::start_tag('ul', array('class' => 'ml'));
650 foreach ($courses as $listitem) {
651 $i++;
652 if ($i == $totalcourses) {
653 $last = true;
654 }
655 $html .= $this->search_listitem($listitem, $courseid, $first, $last);
656 $first = false;
657 }
658 $html .= html_writer::end_tag('ul');
659 $html .= $this->search_pagination($totalcourses, $page, $perpage, true, $search);
660 $html .= $this->course_search_bulk_actions();
661 $html .= html_writer::end_div();
662 return $html;
663 }
664
665 /**
666 * Renderers a search result course list item.
667 *
668 * This function will be called for every course being displayed by course_listing.
669 *
670 * @param course_in_list $course The course to produce HTML for.
671 * @param int $selectedcourse The id of the currently selected course.
672 * @return string
673 */
674 public function search_listitem(course_in_list $course, $selectedcourse) {
675
676 $text = $course->get_formatted_name();
677 $attributes = array(
678 'class' => 'listitem listitem-course list-group-item list-group-item-action',
679 'data-id' => $course->id,
680 'data-selected' => ($selectedcourse == $course->id) ? '1' : '0',
681 'data-visible' => $course->visible ? '1' : '0'
682 );
683 $bulkcourseinput = '';
684 if (coursecat::get($course->category)->can_move_courses_out_of()) {
685 $bulkcourseinput = array(
686 'type' => 'checkbox',
687 'name' => 'bc[]',
688 'value' => $course->id,
689 'class' => 'bulk-action-checkbox',
690 'aria-label' => get_string('bulkactionselect', 'moodle', $text),
691 'data-action' => 'select'
692 );
693 }
694 $viewcourseurl = new moodle_url($this->page->url, array('courseid' => $course->id));
695 $categoryname = coursecat::get($course->category)->get_formatted_name();
696
697 $html = html_writer::start_tag('li', $attributes);
698 $html .= html_writer::start_div('clearfix');
699 $html .= html_writer::start_div('float-left');
700 if ($bulkcourseinput) {
701 $html .= html_writer::empty_tag('input', $bulkcourseinput).'&nbsp;';
702 }
703 $html .= html_writer::end_div();
704 $html .= html_writer::link($viewcourseurl, $text, array('class' => 'float-left coursename'));
705 $html .= html_writer::tag('span', $categoryname, array('class' => 'float-left categoryname'));
706 $html .= html_writer::start_div('float-right');
707 $html .= $this->search_listitem_actions($course);
708 $html .= html_writer::tag('span', s($course->idnumber), array('class' => 'dimmed idnumber'));
709 $html .= html_writer::end_div();
710 $html .= html_writer::end_div();
711 $html .= html_writer::end_tag('li');
712 return $html;
713 }
714
715 /**
716 * Renderers a key value pair of information for display.
717 *
718 * @param string $key
719 * @param string $value
720 * @param string $class
721 * @return string
722 */
723 protected function detail_pair($key, $value, $class ='') {
724 $html = html_writer::start_div('detail-pair row yui3-g '.preg_replace('#[^a-zA-Z0-9_\-]#', '-', $class));
c3c42514 725 $html .= html_writer::div(html_writer::span($key), 'pair-key col-md-3 yui3-u-1-4 font-weight-bold');
3ec69c2e
BB
726 $html .= html_writer::div(html_writer::span($value), 'pair-value col-md-8 yui3-u-3-4');
727 $html .= html_writer::end_div();
728 return $html;
729 }
730
731 /**
732 * A collection of actions for a course.
733 *
734 * @param course_in_list $course The course to display actions for.
735 * @return string
736 */
737 public function course_detail_actions(course_in_list $course) {
738 $actions = \core_course\management\helper::get_course_detail_actions($course);
739 if (empty($actions)) {
740 return '';
741 }
742 $options = array();
743 foreach ($actions as $action) {
744 $options[] = $this->action_link($action['url'], $action['string'], null,
745 array('class' => 'btn btn-sm btn-secondary mr-1 mb-3'));
746 }
747 return html_writer::div(join('', $options), 'listing-actions course-detail-listing-actions');
748 }
749
750}