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