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