[ Index ] |
PHP Cross Reference of moodle-2.8 |
[Summary view] [Print] [Text view]
1 <?php 2 3 // This file is part of Moodle - http://moodle.org/ 4 // 5 // Moodle is free software: you can redistribute it and/or modify 6 // it under the terms of the GNU General Public License as published by 7 // the Free Software Foundation, either version 3 of the License, or 8 // (at your option) any later version. 9 // 10 // Moodle is distributed in the hope that it will be useful, 11 // but WITHOUT ANY WARRANTY; without even the implied warranty of 12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 // GNU General Public License for more details. 14 // 15 // You should have received a copy of the GNU General Public License 16 // along with Moodle. If not, see <http://www.gnu.org/licenses/>. 17 18 /** 19 * Renderer for use with the course section and all the goodness that falls 20 * within it. 21 * 22 * This renderer should contain methods useful to courses, and categories. 23 * 24 * @package moodlecore 25 * @copyright 2010 Sam Hemelryk 26 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 27 */ 28 29 /** 30 * The core course renderer 31 * 32 * Can be retrieved with the following: 33 * $renderer = $PAGE->get_renderer('core','course'); 34 */ 35 class core_course_renderer extends plugin_renderer_base { 36 const COURSECAT_SHOW_COURSES_NONE = 0; /* do not show courses at all */ 37 const COURSECAT_SHOW_COURSES_COUNT = 5; /* do not show courses but show number of courses next to category name */ 38 const COURSECAT_SHOW_COURSES_COLLAPSED = 10; 39 const COURSECAT_SHOW_COURSES_AUTO = 15; /* will choose between collapsed and expanded automatically */ 40 const COURSECAT_SHOW_COURSES_EXPANDED = 20; 41 const COURSECAT_SHOW_COURSES_EXPANDED_WITH_CAT = 30; 42 43 const COURSECAT_TYPE_CATEGORY = 0; 44 const COURSECAT_TYPE_COURSE = 1; 45 46 /** 47 * A cache of strings 48 * @var stdClass 49 */ 50 protected $strings; 51 52 /** 53 * Override the constructor so that we can initialise the string cache 54 * 55 * @param moodle_page $page 56 * @param string $target 57 */ 58 public function __construct(moodle_page $page, $target) { 59 $this->strings = new stdClass; 60 parent::__construct($page, $target); 61 $this->add_modchoosertoggle(); 62 } 63 64 /** 65 * Adds the item in course settings navigation to toggle modchooser 66 * 67 * Theme can overwrite as an empty function to exclude it (for example if theme does not 68 * use modchooser at all) 69 */ 70 protected function add_modchoosertoggle() { 71 global $CFG; 72 73 // Only needs to be done once per page. 74 if (!$this->page->requires->should_create_one_time_item_now('core_course_modchoosertoggle')) { 75 return; 76 } 77 78 if ($this->page->state > moodle_page::STATE_PRINTING_HEADER || 79 $this->page->course->id == SITEID || 80 !$this->page->user_is_editing() || 81 !($context = context_course::instance($this->page->course->id)) || 82 !has_capability('moodle/course:manageactivities', $context) || 83 !course_ajax_enabled($this->page->course) || 84 !($coursenode = $this->page->settingsnav->find('courseadmin', navigation_node::TYPE_COURSE)) || 85 !($turneditingnode = $coursenode->get('turneditingonoff'))) { 86 // Too late, or we are on site page, or we could not find the 87 // adjacent nodes in course settings menu, or we are not allowed to edit. 88 return; 89 } 90 91 if ($this->page->url->compare(new moodle_url('/course/view.php'), URL_MATCH_BASE)) { 92 // We are on the course page, retain the current page params e.g. section. 93 $modchoosertoggleurl = clone($this->page->url); 94 } else { 95 // Edit on the main course page. 96 $modchoosertoggleurl = new moodle_url('/course/view.php', array('id' => $this->page->course->id, 97 'return' => $this->page->url->out_as_local_url(false))); 98 } 99 $modchoosertoggleurl->param('sesskey', sesskey()); 100 if ($usemodchooser = get_user_preferences('usemodchooser', $CFG->modchooserdefault)) { 101 $modchoosertogglestring = get_string('modchooserdisable', 'moodle'); 102 $modchoosertoggleurl->param('modchooser', 'off'); 103 } else { 104 $modchoosertogglestring = get_string('modchooserenable', 'moodle'); 105 $modchoosertoggleurl->param('modchooser', 'on'); 106 } 107 $modchoosertoggle = navigation_node::create($modchoosertogglestring, $modchoosertoggleurl, navigation_node::TYPE_SETTING, null, 'modchoosertoggle'); 108 109 // Insert the modchoosertoggle after the settings node 'turneditingonoff' (navigation_node only has function to insert before, so we insert before and then swap). 110 $coursenode->add_node($modchoosertoggle, 'turneditingonoff'); 111 $turneditingnode->remove(); 112 $coursenode->add_node($turneditingnode, 'modchoosertoggle'); 113 114 $modchoosertoggle->add_class('modchoosertoggle'); 115 $modchoosertoggle->add_class('visibleifjs'); 116 user_preference_allow_ajax_update('usemodchooser', PARAM_BOOL); 117 } 118 119 /** 120 * Renders course info box. 121 * 122 * @param stdClass|course_in_list $course 123 * @return string 124 */ 125 public function course_info_box(stdClass $course) { 126 $content = ''; 127 $content .= $this->output->box_start('generalbox info'); 128 $chelper = new coursecat_helper(); 129 $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED); 130 $content .= $this->coursecat_coursebox($chelper, $course); 131 $content .= $this->output->box_end(); 132 return $content; 133 } 134 135 /** 136 * Renderers a structured array of courses and categories into a nice XHTML tree structure. 137 * 138 * @deprecated since 2.5 139 * 140 * Please see http://docs.moodle.org/dev/Courses_lists_upgrade_to_2.5 141 * 142 * @param array $ignored argument ignored 143 * @return string 144 */ 145 public final function course_category_tree(array $ignored) { 146 debugging('Function core_course_renderer::course_category_tree() is deprecated, please use frontpage_combo_list()', DEBUG_DEVELOPER); 147 return $this->frontpage_combo_list(); 148 } 149 150 /** 151 * Renderers a category for use with course_category_tree 152 * 153 * @deprecated since 2.5 154 * 155 * Please see http://docs.moodle.org/dev/Courses_lists_upgrade_to_2.5 156 * 157 * @param array $category 158 * @param int $depth 159 * @return string 160 */ 161 protected final function course_category_tree_category(stdClass $category, $depth=1) { 162 debugging('Function core_course_renderer::course_category_tree_category() is deprecated', DEBUG_DEVELOPER); 163 return ''; 164 } 165 166 /** 167 * Build the HTML for the module chooser javascript popup 168 * 169 * @param array $modules A set of modules as returned form @see 170 * get_module_metadata 171 * @param object $course The course that will be displayed 172 * @return string The composed HTML for the module 173 */ 174 public function course_modchooser($modules, $course) { 175 if (!$this->page->requires->should_create_one_time_item_now('core_course_modchooser')) { 176 return ''; 177 } 178 179 // Add the module chooser 180 $this->page->requires->yui_module('moodle-course-modchooser', 181 'M.course.init_chooser', 182 array(array('courseid' => $course->id, 'closeButtonTitle' => get_string('close', 'editor'))) 183 ); 184 $this->page->requires->strings_for_js(array( 185 'addresourceoractivity', 186 'modchooserenable', 187 'modchooserdisable', 188 ), 'moodle'); 189 190 // Add the header 191 $header = html_writer::tag('div', get_string('addresourceoractivity', 'moodle'), 192 array('class' => 'hd choosertitle')); 193 194 $formcontent = html_writer::start_tag('form', array('action' => new moodle_url('/course/jumpto.php'), 195 'id' => 'chooserform', 'method' => 'post')); 196 $formcontent .= html_writer::start_tag('div', array('id' => 'typeformdiv')); 197 $formcontent .= html_writer::tag('input', '', array('type' => 'hidden', 'id' => 'course', 198 'name' => 'course', 'value' => $course->id)); 199 $formcontent .= html_writer::tag('input', '', array('type' => 'hidden', 'name' => 'sesskey', 200 'value' => sesskey())); 201 $formcontent .= html_writer::end_tag('div'); 202 203 // Put everything into one tag 'options' 204 $formcontent .= html_writer::start_tag('div', array('class' => 'options')); 205 $formcontent .= html_writer::tag('div', get_string('selectmoduletoviewhelp', 'moodle'), 206 array('class' => 'instruction')); 207 // Put all options into one tag 'alloptions' to allow us to handle scrolling 208 $formcontent .= html_writer::start_tag('div', array('class' => 'alloptions')); 209 210 // Activities 211 $activities = array_filter($modules, create_function('$mod', 'return ($mod->archetype !== MOD_ARCHETYPE_RESOURCE && $mod->archetype !== MOD_ARCHETYPE_SYSTEM);')); 212 if (count($activities)) { 213 $formcontent .= $this->course_modchooser_title('activities'); 214 $formcontent .= $this->course_modchooser_module_types($activities); 215 } 216 217 // Resources 218 $resources = array_filter($modules, create_function('$mod', 'return ($mod->archetype === MOD_ARCHETYPE_RESOURCE);')); 219 if (count($resources)) { 220 $formcontent .= $this->course_modchooser_title('resources'); 221 $formcontent .= $this->course_modchooser_module_types($resources); 222 } 223 224 $formcontent .= html_writer::end_tag('div'); // modoptions 225 $formcontent .= html_writer::end_tag('div'); // types 226 227 $formcontent .= html_writer::start_tag('div', array('class' => 'submitbuttons')); 228 $formcontent .= html_writer::tag('input', '', 229 array('type' => 'submit', 'name' => 'submitbutton', 'class' => 'submitbutton', 'value' => get_string('add'))); 230 $formcontent .= html_writer::tag('input', '', 231 array('type' => 'submit', 'name' => 'addcancel', 'class' => 'addcancel', 'value' => get_string('cancel'))); 232 $formcontent .= html_writer::end_tag('div'); 233 $formcontent .= html_writer::end_tag('form'); 234 235 // Wrap the whole form in a div 236 $formcontent = html_writer::tag('div', $formcontent, array('id' => 'chooseform')); 237 238 // Put all of the content together 239 $content = $formcontent; 240 241 $content = html_writer::tag('div', $content, array('class' => 'choosercontainer')); 242 return $header . html_writer::tag('div', $content, array('class' => 'chooserdialoguebody')); 243 } 244 245 /** 246 * Build the HTML for a specified set of modules 247 * 248 * @param array $modules A set of modules as used by the 249 * course_modchooser_module function 250 * @return string The composed HTML for the module 251 */ 252 protected function course_modchooser_module_types($modules) { 253 $return = ''; 254 foreach ($modules as $module) { 255 if (!isset($module->types)) { 256 $return .= $this->course_modchooser_module($module); 257 } else { 258 $return .= $this->course_modchooser_module($module, array('nonoption')); 259 foreach ($module->types as $type) { 260 $return .= $this->course_modchooser_module($type, array('option', 'subtype')); 261 } 262 } 263 } 264 return $return; 265 } 266 267 /** 268 * Return the HTML for the specified module adding any required classes 269 * 270 * @param object $module An object containing the title, and link. An 271 * icon, and help text may optionally be specified. If the module 272 * contains subtypes in the types option, then these will also be 273 * displayed. 274 * @param array $classes Additional classes to add to the encompassing 275 * div element 276 * @return string The composed HTML for the module 277 */ 278 protected function course_modchooser_module($module, $classes = array('option')) { 279 $output = ''; 280 $output .= html_writer::start_tag('div', array('class' => implode(' ', $classes))); 281 $output .= html_writer::start_tag('label', array('for' => 'module_' . $module->name)); 282 if (!isset($module->types)) { 283 $output .= html_writer::tag('input', '', array('type' => 'radio', 284 'name' => 'jumplink', 'id' => 'module_' . $module->name, 'value' => $module->link)); 285 } 286 287 $output .= html_writer::start_tag('span', array('class' => 'modicon')); 288 if (isset($module->icon)) { 289 // Add an icon if we have one 290 $output .= $module->icon; 291 } 292 $output .= html_writer::end_tag('span'); 293 294 $output .= html_writer::tag('span', $module->title, array('class' => 'typename')); 295 if (!isset($module->help)) { 296 // Add help if found 297 $module->help = get_string('nohelpforactivityorresource', 'moodle'); 298 } 299 300 // Format the help text using markdown with the following options 301 $options = new stdClass(); 302 $options->trusted = false; 303 $options->noclean = false; 304 $options->smiley = false; 305 $options->filter = false; 306 $options->para = true; 307 $options->newlines = false; 308 $options->overflowdiv = false; 309 $module->help = format_text($module->help, FORMAT_MARKDOWN, $options); 310 $output .= html_writer::tag('span', $module->help, array('class' => 'typesummary')); 311 $output .= html_writer::end_tag('label'); 312 $output .= html_writer::end_tag('div'); 313 314 return $output; 315 } 316 317 protected function course_modchooser_title($title, $identifier = null) { 318 $module = new stdClass(); 319 $module->name = $title; 320 $module->types = array(); 321 $module->title = get_string($title, $identifier); 322 $module->help = ''; 323 return $this->course_modchooser_module($module, array('moduletypetitle')); 324 } 325 326 /** 327 * Renders HTML for displaying the sequence of course module editing buttons 328 * 329 * @see course_get_cm_edit_actions() 330 * 331 * @param action_link[] $actions Array of action_link objects 332 * @param cm_info $mod The module we are displaying actions for. 333 * @param array $displayoptions additional display options: 334 * ownerselector => A JS/CSS selector that can be used to find an cm node. 335 * If specified the owning node will be given the class 'action-menu-shown' when the action 336 * menu is being displayed. 337 * constraintselector => A JS/CSS selector that can be used to find the parent node for which to constrain 338 * the action menu to when it is being displayed. 339 * donotenhance => If set to true the action menu that gets displayed won't be enhanced by JS. 340 * @return string 341 */ 342 public function course_section_cm_edit_actions($actions, cm_info $mod = null, $displayoptions = array()) { 343 global $CFG; 344 345 if (empty($actions)) { 346 return ''; 347 } 348 349 if (isset($displayoptions['ownerselector'])) { 350 $ownerselector = $displayoptions['ownerselector']; 351 } else if ($mod) { 352 $ownerselector = '#module-'.$mod->id; 353 } else { 354 debugging('You should upgrade your call to '.__FUNCTION__.' and provide $mod', DEBUG_DEVELOPER); 355 $ownerselector = 'li.activity'; 356 } 357 358 if (isset($displayoptions['constraintselector'])) { 359 $constraint = $displayoptions['constraintselector']; 360 } else { 361 $constraint = '.course-content'; 362 } 363 364 $menu = new action_menu(); 365 $menu->set_owner_selector($ownerselector); 366 $menu->set_constraint($constraint); 367 $menu->set_alignment(action_menu::TR, action_menu::BR); 368 $menu->set_menu_trigger(get_string('edit')); 369 if (isset($CFG->modeditingmenu) && !$CFG->modeditingmenu || !empty($displayoptions['donotenhance'])) { 370 $menu->do_not_enhance(); 371 372 // Swap the left/right icons. 373 // Normally we have have right, then left but this does not 374 // make sense when modactionmenu is disabled. 375 $moveright = null; 376 $_actions = array(); 377 foreach ($actions as $key => $value) { 378 if ($key === 'moveright') { 379 380 // Save moveright for later. 381 $moveright = $value; 382 } else if ($moveright) { 383 384 // This assumes that the order was moveright, moveleft. 385 // If we have a moveright, then we should place it immediately after the current value. 386 $_actions[$key] = $value; 387 $_actions['moveright'] = $moveright; 388 389 // Clear the value to prevent it being used multiple times. 390 $moveright = null; 391 } else { 392 393 $_actions[$key] = $value; 394 } 395 } 396 $actions = $_actions; 397 unset($_actions); 398 } 399 foreach ($actions as $action) { 400 if ($action instanceof action_menu_link) { 401 $action->add_class('cm-edit-action'); 402 } 403 $menu->add($action); 404 } 405 $menu->attributes['class'] .= ' section-cm-edit-actions commands'; 406 407 // Prioritise the menu ahead of all other actions. 408 $menu->prioritise = true; 409 410 return $this->render($menu); 411 } 412 413 /** 414 * Renders HTML for the menus to add activities and resources to the current course 415 * 416 * Note, if theme overwrites this function and it does not use modchooser, 417 * see also {@link core_course_renderer::add_modchoosertoggle()} 418 * 419 * @param stdClass $course 420 * @param int $section relative section number (field course_sections.section) 421 * @param int $sectionreturn The section to link back to 422 * @param array $displayoptions additional display options, for example blocks add 423 * option 'inblock' => true, suggesting to display controls vertically 424 * @return string 425 */ 426 function course_section_add_cm_control($course, $section, $sectionreturn = null, $displayoptions = array()) { 427 global $CFG; 428 429 $vertical = !empty($displayoptions['inblock']); 430 431 // check to see if user can add menus and there are modules to add 432 if (!has_capability('moodle/course:manageactivities', context_course::instance($course->id)) 433 || !$this->page->user_is_editing() 434 || !($modnames = get_module_types_names()) || empty($modnames)) { 435 return ''; 436 } 437 438 // Retrieve all modules with associated metadata 439 $modules = get_module_metadata($course, $modnames, $sectionreturn); 440 $urlparams = array('section' => $section); 441 442 // We'll sort resources and activities into two lists 443 $activities = array(MOD_CLASS_ACTIVITY => array(), MOD_CLASS_RESOURCE => array()); 444 445 foreach ($modules as $module) { 446 if (isset($module->types)) { 447 // This module has a subtype 448 // NOTE: this is legacy stuff, module subtypes are very strongly discouraged!! 449 $subtypes = array(); 450 foreach ($module->types as $subtype) { 451 $link = $subtype->link->out(true, $urlparams); 452 $subtypes[$link] = $subtype->title; 453 } 454 455 // Sort module subtypes into the list 456 $activityclass = MOD_CLASS_ACTIVITY; 457 if ($module->archetype == MOD_CLASS_RESOURCE) { 458 $activityclass = MOD_CLASS_RESOURCE; 459 } 460 if (!empty($module->title)) { 461 // This grouping has a name 462 $activities[$activityclass][] = array($module->title => $subtypes); 463 } else { 464 // This grouping does not have a name 465 $activities[$activityclass] = array_merge($activities[$activityclass], $subtypes); 466 } 467 } else { 468 // This module has no subtypes 469 $activityclass = MOD_CLASS_ACTIVITY; 470 if ($module->archetype == MOD_ARCHETYPE_RESOURCE) { 471 $activityclass = MOD_CLASS_RESOURCE; 472 } else if ($module->archetype === MOD_ARCHETYPE_SYSTEM) { 473 // System modules cannot be added by user, do not add to dropdown 474 continue; 475 } 476 $link = $module->link->out(true, $urlparams); 477 $activities[$activityclass][$link] = $module->title; 478 } 479 } 480 481 $straddactivity = get_string('addactivity'); 482 $straddresource = get_string('addresource'); 483 $sectionname = get_section_name($course, $section); 484 $strresourcelabel = get_string('addresourcetosection', null, $sectionname); 485 $stractivitylabel = get_string('addactivitytosection', null, $sectionname); 486 487 $output = html_writer::start_tag('div', array('class' => 'section_add_menus', 'id' => 'add_menus-section-' . $section)); 488 489 if (!$vertical) { 490 $output .= html_writer::start_tag('div', array('class' => 'horizontal')); 491 } 492 493 if (!empty($activities[MOD_CLASS_RESOURCE])) { 494 $select = new url_select($activities[MOD_CLASS_RESOURCE], '', array(''=>$straddresource), "ressection$section"); 495 $select->set_help_icon('resources'); 496 $select->set_label($strresourcelabel, array('class' => 'accesshide')); 497 $output .= $this->output->render($select); 498 } 499 500 if (!empty($activities[MOD_CLASS_ACTIVITY])) { 501 $select = new url_select($activities[MOD_CLASS_ACTIVITY], '', array(''=>$straddactivity), "section$section"); 502 $select->set_help_icon('activities'); 503 $select->set_label($stractivitylabel, array('class' => 'accesshide')); 504 $output .= $this->output->render($select); 505 } 506 507 if (!$vertical) { 508 $output .= html_writer::end_tag('div'); 509 } 510 511 $output .= html_writer::end_tag('div'); 512 513 if (course_ajax_enabled($course) && $course->id == $this->page->course->id) { 514 // modchooser can be added only for the current course set on the page! 515 $straddeither = get_string('addresourceoractivity'); 516 // The module chooser link 517 $modchooser = html_writer::start_tag('div', array('class' => 'mdl-right')); 518 $modchooser.= html_writer::start_tag('div', array('class' => 'section-modchooser')); 519 $icon = $this->output->pix_icon('t/add', ''); 520 $span = html_writer::tag('span', $straddeither, array('class' => 'section-modchooser-text')); 521 $modchooser .= html_writer::tag('span', $icon . $span, array('class' => 'section-modchooser-link')); 522 $modchooser.= html_writer::end_tag('div'); 523 $modchooser.= html_writer::end_tag('div'); 524 525 // Wrap the normal output in a noscript div 526 $usemodchooser = get_user_preferences('usemodchooser', $CFG->modchooserdefault); 527 if ($usemodchooser) { 528 $output = html_writer::tag('div', $output, array('class' => 'hiddenifjs addresourcedropdown')); 529 $modchooser = html_writer::tag('div', $modchooser, array('class' => 'visibleifjs addresourcemodchooser')); 530 } else { 531 // If the module chooser is disabled, we need to ensure that the dropdowns are shown even if javascript is disabled 532 $output = html_writer::tag('div', $output, array('class' => 'show addresourcedropdown')); 533 $modchooser = html_writer::tag('div', $modchooser, array('class' => 'hide addresourcemodchooser')); 534 } 535 $output = $this->course_modchooser($modules, $course) . $modchooser . $output; 536 } 537 538 return $output; 539 } 540 541 /** 542 * Renders html to display a course search form 543 * 544 * @param string $value default value to populate the search field 545 * @param string $format display format - 'plain' (default), 'short' or 'navbar' 546 * @return string 547 */ 548 function course_search_form($value = '', $format = 'plain') { 549 static $count = 0; 550 $formid = 'coursesearch'; 551 if ((++$count) > 1) { 552 $formid .= $count; 553 } 554 555 switch ($format) { 556 case 'navbar' : 557 $formid = 'coursesearchnavbar'; 558 $inputid = 'navsearchbox'; 559 $inputsize = 20; 560 break; 561 case 'short' : 562 $inputid = 'shortsearchbox'; 563 $inputsize = 12; 564 break; 565 default : 566 $inputid = 'coursesearchbox'; 567 $inputsize = 30; 568 } 569 570 $strsearchcourses= get_string("searchcourses"); 571 $searchurl = new moodle_url('/course/search.php'); 572 573 $output = html_writer::start_tag('form', array('id' => $formid, 'action' => $searchurl, 'method' => 'get')); 574 $output .= html_writer::start_tag('fieldset', array('class' => 'coursesearchbox invisiblefieldset')); 575 $output .= html_writer::tag('label', $strsearchcourses.': ', array('for' => $inputid)); 576 $output .= html_writer::empty_tag('input', array('type' => 'text', 'id' => $inputid, 577 'size' => $inputsize, 'name' => 'search', 'value' => s($value))); 578 $output .= html_writer::empty_tag('input', array('type' => 'submit', 579 'value' => get_string('go'))); 580 $output .= html_writer::end_tag('fieldset'); 581 $output .= html_writer::end_tag('form'); 582 583 return $output; 584 } 585 586 /** 587 * Renders html for completion box on course page 588 * 589 * If completion is disabled, returns empty string 590 * If completion is automatic, returns an icon of the current completion state 591 * If completion is manual, returns a form (with an icon inside) that allows user to 592 * toggle completion 593 * 594 * @param stdClass $course course object 595 * @param completion_info $completioninfo completion info for the course, it is recommended 596 * to fetch once for all modules in course/section for performance 597 * @param cm_info $mod module to show completion for 598 * @param array $displayoptions display options, not used in core 599 * @return string 600 */ 601 public function course_section_cm_completion($course, &$completioninfo, cm_info $mod, $displayoptions = array()) { 602 global $CFG; 603 $output = ''; 604 if (!empty($displayoptions['hidecompletion']) || !isloggedin() || isguestuser() || !$mod->uservisible) { 605 return $output; 606 } 607 if ($completioninfo === null) { 608 $completioninfo = new completion_info($course); 609 } 610 $completion = $completioninfo->is_enabled($mod); 611 if ($completion == COMPLETION_TRACKING_NONE) { 612 if ($this->page->user_is_editing()) { 613 $output .= html_writer::span(' ', 'filler'); 614 } 615 return $output; 616 } 617 618 $completiondata = $completioninfo->get_data($mod, true); 619 $completionicon = ''; 620 621 if ($this->page->user_is_editing()) { 622 switch ($completion) { 623 case COMPLETION_TRACKING_MANUAL : 624 $completionicon = 'manual-enabled'; break; 625 case COMPLETION_TRACKING_AUTOMATIC : 626 $completionicon = 'auto-enabled'; break; 627 } 628 } else if ($completion == COMPLETION_TRACKING_MANUAL) { 629 switch($completiondata->completionstate) { 630 case COMPLETION_INCOMPLETE: 631 $completionicon = 'manual-n'; break; 632 case COMPLETION_COMPLETE: 633 $completionicon = 'manual-y'; break; 634 } 635 } else { // Automatic 636 switch($completiondata->completionstate) { 637 case COMPLETION_INCOMPLETE: 638 $completionicon = 'auto-n'; break; 639 case COMPLETION_COMPLETE: 640 $completionicon = 'auto-y'; break; 641 case COMPLETION_COMPLETE_PASS: 642 $completionicon = 'auto-pass'; break; 643 case COMPLETION_COMPLETE_FAIL: 644 $completionicon = 'auto-fail'; break; 645 } 646 } 647 if ($completionicon) { 648 $formattedname = $mod->get_formatted_name(); 649 $imgalt = get_string('completion-alt-' . $completionicon, 'completion', $formattedname); 650 651 if ($this->page->user_is_editing()) { 652 // When editing, the icon is just an image. 653 $completionpixicon = new pix_icon('i/completion-'.$completionicon, $imgalt, '', 654 array('title' => $imgalt, 'class' => 'iconsmall')); 655 $output .= html_writer::tag('span', $this->output->render($completionpixicon), 656 array('class' => 'autocompletion')); 657 } else if ($completion == COMPLETION_TRACKING_MANUAL) { 658 $imgtitle = get_string('completion-title-' . $completionicon, 'completion', $formattedname); 659 $newstate = 660 $completiondata->completionstate == COMPLETION_COMPLETE 661 ? COMPLETION_INCOMPLETE 662 : COMPLETION_COMPLETE; 663 // In manual mode the icon is a toggle form... 664 665 // If this completion state is used by the 666 // conditional activities system, we need to turn 667 // off the JS. 668 $extraclass = ''; 669 if (!empty($CFG->enableavailability) && 670 core_availability\info::completion_value_used($course, $mod->id)) { 671 $extraclass = ' preventjs'; 672 } 673 $output .= html_writer::start_tag('form', array('method' => 'post', 674 'action' => new moodle_url('/course/togglecompletion.php'), 675 'class' => 'togglecompletion'. $extraclass)); 676 $output .= html_writer::start_tag('div'); 677 $output .= html_writer::empty_tag('input', array( 678 'type' => 'hidden', 'name' => 'id', 'value' => $mod->id)); 679 $output .= html_writer::empty_tag('input', array( 680 'type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())); 681 $output .= html_writer::empty_tag('input', array( 682 'type' => 'hidden', 'name' => 'modulename', 'value' => $mod->name)); 683 $output .= html_writer::empty_tag('input', array( 684 'type' => 'hidden', 'name' => 'completionstate', 'value' => $newstate)); 685 $output .= html_writer::empty_tag('input', array( 686 'type' => 'image', 687 'src' => $this->output->pix_url('i/completion-'.$completionicon), 688 'alt' => $imgalt, 'title' => $imgtitle, 689 'aria-live' => 'polite')); 690 $output .= html_writer::end_tag('div'); 691 $output .= html_writer::end_tag('form'); 692 } else { 693 // In auto mode, the icon is just an image. 694 $completionpixicon = new pix_icon('i/completion-'.$completionicon, $imgalt, '', 695 array('title' => $imgalt)); 696 $output .= html_writer::tag('span', $this->output->render($completionpixicon), 697 array('class' => 'autocompletion')); 698 } 699 } 700 return $output; 701 } 702 703 /** 704 * Checks if course module has any conditions that may make it unavailable for 705 * all or some of the students 706 * 707 * This function is internal and is only used to create CSS classes for the module name/text 708 * 709 * @param cm_info $mod 710 * @return bool 711 */ 712 protected function is_cm_conditionally_hidden(cm_info $mod) { 713 global $CFG; 714 $conditionalhidden = false; 715 if (!empty($CFG->enableavailability)) { 716 $info = new \core_availability\info_module($mod); 717 $conditionalhidden = !$info->is_available_for_all(); 718 } 719 return $conditionalhidden; 720 } 721 722 /** 723 * Renders html to display a name with the link to the course module on a course page 724 * 725 * If module is unavailable for user but still needs to be displayed 726 * in the list, just the name is returned without a link 727 * 728 * Note, that for course modules that never have separate pages (i.e. labels) 729 * this function return an empty string 730 * 731 * @param cm_info $mod 732 * @param array $displayoptions 733 * @return string 734 */ 735 public function course_section_cm_name(cm_info $mod, $displayoptions = array()) { 736 global $CFG; 737 $output = ''; 738 if (!$mod->uservisible && empty($mod->availableinfo)) { 739 // nothing to be displayed to the user 740 return $output; 741 } 742 $url = $mod->url; 743 if (!$url) { 744 return $output; 745 } 746 747 //Accessibility: for files get description via icon, this is very ugly hack! 748 $instancename = $mod->get_formatted_name(); 749 $altname = $mod->modfullname; 750 // Avoid unnecessary duplication: if e.g. a forum name already 751 // includes the word forum (or Forum, etc) then it is unhelpful 752 // to include that in the accessible description that is added. 753 if (false !== strpos(core_text::strtolower($instancename), 754 core_text::strtolower($altname))) { 755 $altname = ''; 756 } 757 // File type after name, for alphabetic lists (screen reader). 758 if ($altname) { 759 $altname = get_accesshide(' '.$altname); 760 } 761 762 // For items which are hidden but available to current user 763 // ($mod->uservisible), we show those as dimmed only if the user has 764 // viewhiddenactivities, so that teachers see 'items which might not 765 // be available to some students' dimmed but students do not see 'item 766 // which is actually available to current student' dimmed. 767 $linkclasses = ''; 768 $accesstext = ''; 769 $textclasses = ''; 770 if ($mod->uservisible) { 771 $conditionalhidden = $this->is_cm_conditionally_hidden($mod); 772 $accessiblebutdim = (!$mod->visible || $conditionalhidden) && 773 has_capability('moodle/course:viewhiddenactivities', $mod->context); 774 if ($accessiblebutdim) { 775 $linkclasses .= ' dimmed'; 776 $textclasses .= ' dimmed_text'; 777 if ($conditionalhidden) { 778 $linkclasses .= ' conditionalhidden'; 779 $textclasses .= ' conditionalhidden'; 780 } 781 // Show accessibility note only if user can access the module himself. 782 $accesstext = get_accesshide(get_string('hiddenfromstudents').':'. $mod->modfullname); 783 } 784 } else { 785 $linkclasses .= ' dimmed'; 786 $textclasses .= ' dimmed_text'; 787 } 788 789 // Get on-click attribute value if specified and decode the onclick - it 790 // has already been encoded for display (puke). 791 $onclick = htmlspecialchars_decode($mod->onclick, ENT_QUOTES); 792 793 $groupinglabel = $mod->get_grouping_label($textclasses); 794 795 // Display link itself. 796 $activitylink = html_writer::empty_tag('img', array('src' => $mod->get_icon_url(), 797 'class' => 'iconlarge activityicon', 'alt' => ' ', 'role' => 'presentation')) . $accesstext . 798 html_writer::tag('span', $instancename . $altname, array('class' => 'instancename')); 799 if ($mod->uservisible) { 800 $output .= html_writer::link($url, $activitylink, array('class' => $linkclasses, 'onclick' => $onclick)) . 801 $groupinglabel; 802 } else { 803 // We may be displaying this just in order to show information 804 // about visibility, without the actual link ($mod->uservisible) 805 $output .= html_writer::tag('div', $activitylink, array('class' => $textclasses)) . 806 $groupinglabel; 807 } 808 return $output; 809 } 810 811 /** 812 * Renders html to display the module content on the course page (i.e. text of the labels) 813 * 814 * @param cm_info $mod 815 * @param array $displayoptions 816 * @return string 817 */ 818 public function course_section_cm_text(cm_info $mod, $displayoptions = array()) { 819 $output = ''; 820 if (!$mod->uservisible && empty($mod->availableinfo)) { 821 // nothing to be displayed to the user 822 return $output; 823 } 824 $content = $mod->get_formatted_content(array('overflowdiv' => true, 'noclean' => true)); 825 $accesstext = ''; 826 $textclasses = ''; 827 if ($mod->uservisible) { 828 $conditionalhidden = $this->is_cm_conditionally_hidden($mod); 829 $accessiblebutdim = (!$mod->visible || $conditionalhidden) && 830 has_capability('moodle/course:viewhiddenactivities', $mod->context); 831 if ($accessiblebutdim) { 832 $textclasses .= ' dimmed_text'; 833 if ($conditionalhidden) { 834 $textclasses .= ' conditionalhidden'; 835 } 836 // Show accessibility note only if user can access the module himself. 837 $accesstext = get_accesshide(get_string('hiddenfromstudents').':'. $mod->modfullname); 838 } 839 } else { 840 $textclasses .= ' dimmed_text'; 841 } 842 if ($mod->url) { 843 if ($content) { 844 // If specified, display extra content after link. 845 $output = html_writer::tag('div', $content, array('class' => 846 trim('contentafterlink ' . $textclasses))); 847 } 848 } else { 849 $groupinglabel = $mod->get_grouping_label($textclasses); 850 851 // No link, so display only content. 852 $output = html_writer::tag('div', $accesstext . $content . $groupinglabel, 853 array('class' => 'contentwithoutlink ' . $textclasses)); 854 } 855 return $output; 856 } 857 858 /** 859 * Renders HTML to show course module availability information (for someone who isn't allowed 860 * to see the activity itself, or for staff) 861 * 862 * @param cm_info $mod 863 * @param array $displayoptions 864 * @return string 865 */ 866 public function course_section_cm_availability(cm_info $mod, $displayoptions = array()) { 867 global $CFG; 868 if (!$mod->uservisible) { 869 // this is a student who is not allowed to see the module but might be allowed 870 // to see availability info (i.e. "Available from ...") 871 if (!empty($mod->availableinfo)) { 872 $formattedinfo = \core_availability\info::format_info( 873 $mod->availableinfo, $mod->get_course()); 874 $output = html_writer::tag('div', $formattedinfo, array('class' => 'availabilityinfo')); 875 } 876 return $output; 877 } 878 // this is a teacher who is allowed to see module but still should see the 879 // information that module is not available to all/some students 880 $modcontext = context_module::instance($mod->id); 881 $canviewhidden = has_capability('moodle/course:viewhiddenactivities', $modcontext); 882 if ($canviewhidden && !empty($CFG->enableavailability)) { 883 // Don't add availability information if user is not editing and activity is hidden. 884 if ($mod->visible || $this->page->user_is_editing()) { 885 $hidinfoclass = ''; 886 if (!$mod->visible) { 887 $hidinfoclass = 'hide'; 888 } 889 $ci = new \core_availability\info_module($mod); 890 $fullinfo = $ci->get_full_information(); 891 if ($fullinfo) { 892 $formattedinfo = \core_availability\info::format_info( 893 $fullinfo, $mod->get_course()); 894 return html_writer::div($formattedinfo, 'availabilityinfo ' . $hidinfoclass); 895 } 896 } 897 } 898 return ''; 899 } 900 901 /** 902 * Renders HTML to display one course module for display within a section. 903 * 904 * This function calls: 905 * {@link core_course_renderer::course_section_cm()} 906 * 907 * @param stdClass $course 908 * @param completion_info $completioninfo 909 * @param cm_info $mod 910 * @param int|null $sectionreturn 911 * @param array $displayoptions 912 * @return String 913 */ 914 public function course_section_cm_list_item($course, &$completioninfo, cm_info $mod, $sectionreturn, $displayoptions = array()) { 915 $output = ''; 916 if ($modulehtml = $this->course_section_cm($course, $completioninfo, $mod, $sectionreturn, $displayoptions)) { 917 $modclasses = 'activity ' . $mod->modname . ' modtype_' . $mod->modname . ' ' . $mod->extraclasses; 918 $output .= html_writer::tag('li', $modulehtml, array('class' => $modclasses, 'id' => 'module-' . $mod->id)); 919 } 920 return $output; 921 } 922 923 /** 924 * Renders HTML to display one course module in a course section 925 * 926 * This includes link, content, availability, completion info and additional information 927 * that module type wants to display (i.e. number of unread forum posts) 928 * 929 * This function calls: 930 * {@link core_course_renderer::course_section_cm_name()} 931 * {@link core_course_renderer::course_section_cm_text()} 932 * {@link core_course_renderer::course_section_cm_availability()} 933 * {@link core_course_renderer::course_section_cm_completion()} 934 * {@link course_get_cm_edit_actions()} 935 * {@link core_course_renderer::course_section_cm_edit_actions()} 936 * 937 * @param stdClass $course 938 * @param completion_info $completioninfo 939 * @param cm_info $mod 940 * @param int|null $sectionreturn 941 * @param array $displayoptions 942 * @return string 943 */ 944 public function course_section_cm($course, &$completioninfo, cm_info $mod, $sectionreturn, $displayoptions = array()) { 945 $output = ''; 946 // We return empty string (because course module will not be displayed at all) 947 // if: 948 // 1) The activity is not visible to users 949 // and 950 // 2) The 'availableinfo' is empty, i.e. the activity was 951 // hidden in a way that leaves no info, such as using the 952 // eye icon. 953 if (!$mod->uservisible && empty($mod->availableinfo)) { 954 return $output; 955 } 956 957 $indentclasses = 'mod-indent'; 958 if (!empty($mod->indent)) { 959 $indentclasses .= ' mod-indent-'.$mod->indent; 960 if ($mod->indent > 15) { 961 $indentclasses .= ' mod-indent-huge'; 962 } 963 } 964 965 $output .= html_writer::start_tag('div'); 966 967 if ($this->page->user_is_editing()) { 968 $output .= course_get_cm_move($mod, $sectionreturn); 969 } 970 971 $output .= html_writer::start_tag('div', array('class' => 'mod-indent-outer')); 972 973 // This div is used to indent the content. 974 $output .= html_writer::div('', $indentclasses); 975 976 // Start a wrapper for the actual content to keep the indentation consistent 977 $output .= html_writer::start_tag('div'); 978 979 // Display the link to the module (or do nothing if module has no url) 980 $cmname = $this->course_section_cm_name($mod, $displayoptions); 981 982 if (!empty($cmname)) { 983 // Start the div for the activity title, excluding the edit icons. 984 $output .= html_writer::start_tag('div', array('class' => 'activityinstance')); 985 $output .= $cmname; 986 987 988 if ($this->page->user_is_editing()) { 989 $output .= ' ' . course_get_cm_rename_action($mod, $sectionreturn); 990 } 991 992 // Module can put text after the link (e.g. forum unread) 993 $output .= $mod->afterlink; 994 995 // Closing the tag which contains everything but edit icons. Content part of the module should not be part of this. 996 $output .= html_writer::end_tag('div'); // .activityinstance 997 } 998 999 // If there is content but NO link (eg label), then display the 1000 // content here (BEFORE any icons). In this case cons must be 1001 // displayed after the content so that it makes more sense visually 1002 // and for accessibility reasons, e.g. if you have a one-line label 1003 // it should work similarly (at least in terms of ordering) to an 1004 // activity. 1005 $contentpart = $this->course_section_cm_text($mod, $displayoptions); 1006 $url = $mod->url; 1007 if (empty($url)) { 1008 $output .= $contentpart; 1009 } 1010 1011 $modicons = ''; 1012 if ($this->page->user_is_editing()) { 1013 $editactions = course_get_cm_edit_actions($mod, $mod->indent, $sectionreturn); 1014 $modicons .= ' '. $this->course_section_cm_edit_actions($editactions, $mod, $displayoptions); 1015 $modicons .= $mod->afterediticons; 1016 } 1017 1018 $modicons .= $this->course_section_cm_completion($course, $completioninfo, $mod, $displayoptions); 1019 1020 if (!empty($modicons)) { 1021 $output .= html_writer::span($modicons, 'actions'); 1022 } 1023 1024 // If there is content AND a link, then display the content here 1025 // (AFTER any icons). Otherwise it was displayed before 1026 if (!empty($url)) { 1027 $output .= $contentpart; 1028 } 1029 1030 // show availability info (if module is not available) 1031 $output .= $this->course_section_cm_availability($mod, $displayoptions); 1032 1033 $output .= html_writer::end_tag('div'); // $indentclasses 1034 1035 // End of indentation div. 1036 $output .= html_writer::end_tag('div'); 1037 1038 $output .= html_writer::end_tag('div'); 1039 return $output; 1040 } 1041 1042 /** 1043 * Renders HTML to display a list of course modules in a course section 1044 * Also displays "move here" controls in Javascript-disabled mode 1045 * 1046 * This function calls {@link core_course_renderer::course_section_cm()} 1047 * 1048 * @param stdClass $course course object 1049 * @param int|stdClass|section_info $section relative section number or section object 1050 * @param int $sectionreturn section number to return to 1051 * @param int $displayoptions 1052 * @return void 1053 */ 1054 public function course_section_cm_list($course, $section, $sectionreturn = null, $displayoptions = array()) { 1055 global $USER; 1056 1057 $output = ''; 1058 $modinfo = get_fast_modinfo($course); 1059 if (is_object($section)) { 1060 $section = $modinfo->get_section_info($section->section); 1061 } else { 1062 $section = $modinfo->get_section_info($section); 1063 } 1064 $completioninfo = new completion_info($course); 1065 1066 // check if we are currently in the process of moving a module with JavaScript disabled 1067 $ismoving = $this->page->user_is_editing() && ismoving($course->id); 1068 if ($ismoving) { 1069 $movingpix = new pix_icon('movehere', get_string('movehere'), 'moodle', array('class' => 'movetarget')); 1070 $strmovefull = strip_tags(get_string("movefull", "", "'$USER->activitycopyname'")); 1071 } 1072 1073 // Get the list of modules visible to user (excluding the module being moved if there is one) 1074 $moduleshtml = array(); 1075 if (!empty($modinfo->sections[$section->section])) { 1076 foreach ($modinfo->sections[$section->section] as $modnumber) { 1077 $mod = $modinfo->cms[$modnumber]; 1078 1079 if ($ismoving and $mod->id == $USER->activitycopy) { 1080 // do not display moving mod 1081 continue; 1082 } 1083 1084 if ($modulehtml = $this->course_section_cm_list_item($course, 1085 $completioninfo, $mod, $sectionreturn, $displayoptions)) { 1086 $moduleshtml[$modnumber] = $modulehtml; 1087 } 1088 } 1089 } 1090 1091 $sectionoutput = ''; 1092 if (!empty($moduleshtml) || $ismoving) { 1093 foreach ($moduleshtml as $modnumber => $modulehtml) { 1094 if ($ismoving) { 1095 $movingurl = new moodle_url('/course/mod.php', array('moveto' => $modnumber, 'sesskey' => sesskey())); 1096 $sectionoutput .= html_writer::tag('li', 1097 html_writer::link($movingurl, $this->output->render($movingpix), array('title' => $strmovefull)), 1098 array('class' => 'movehere')); 1099 } 1100 1101 $sectionoutput .= $modulehtml; 1102 } 1103 1104 if ($ismoving) { 1105 $movingurl = new moodle_url('/course/mod.php', array('movetosection' => $section->id, 'sesskey' => sesskey())); 1106 $sectionoutput .= html_writer::tag('li', 1107 html_writer::link($movingurl, $this->output->render($movingpix), array('title' => $strmovefull)), 1108 array('class' => 'movehere')); 1109 } 1110 } 1111 1112 // Always output the section module list. 1113 $output .= html_writer::tag('ul', $sectionoutput, array('class' => 'section img-text')); 1114 1115 return $output; 1116 } 1117 1118 /** 1119 * Displays a custom list of courses with paging bar if necessary 1120 * 1121 * If $paginationurl is specified but $totalcount is not, the link 'View more' 1122 * appears under the list. 1123 * 1124 * If both $paginationurl and $totalcount are specified, and $totalcount is 1125 * bigger than count($courses), a paging bar is displayed above and under the 1126 * courses list. 1127 * 1128 * @param array $courses array of course records (or instances of course_in_list) to show on this page 1129 * @param bool $showcategoryname whether to add category name to the course description 1130 * @param string $additionalclasses additional CSS classes to add to the div.courses 1131 * @param moodle_url $paginationurl url to view more or url to form links to the other pages in paging bar 1132 * @param int $totalcount total number of courses on all pages, if omitted $paginationurl will be displayed as 'View more' link 1133 * @param int $page current page number (defaults to 0 referring to the first page) 1134 * @param int $perpage number of records per page (defaults to $CFG->coursesperpage) 1135 * @return string 1136 */ 1137 public function courses_list($courses, $showcategoryname = false, $additionalclasses = null, $paginationurl = null, $totalcount = null, $page = 0, $perpage = null) { 1138 global $CFG; 1139 // create instance of coursecat_helper to pass display options to function rendering courses list 1140 $chelper = new coursecat_helper(); 1141 if ($showcategoryname) { 1142 $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED_WITH_CAT); 1143 } else { 1144 $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED); 1145 } 1146 if ($totalcount !== null && $paginationurl !== null) { 1147 // add options to display pagination 1148 if ($perpage === null) { 1149 $perpage = $CFG->coursesperpage; 1150 } 1151 $chelper->set_courses_display_options(array( 1152 'limit' => $perpage, 1153 'offset' => ((int)$page) * $perpage, 1154 'paginationurl' => $paginationurl, 1155 )); 1156 } else if ($paginationurl !== null) { 1157 // add options to display 'View more' link 1158 $chelper->set_courses_display_options(array('viewmoreurl' => $paginationurl)); 1159 $totalcount = count($courses) + 1; // has to be bigger than count($courses) otherwise link will not be displayed 1160 } 1161 $chelper->set_attributes(array('class' => $additionalclasses)); 1162 $content = $this->coursecat_courses($chelper, $courses, $totalcount); 1163 return $content; 1164 } 1165 1166 /** 1167 * Displays one course in the list of courses. 1168 * 1169 * This is an internal function, to display an information about just one course 1170 * please use {@link core_course_renderer::course_info_box()} 1171 * 1172 * @param coursecat_helper $chelper various display options 1173 * @param course_in_list|stdClass $course 1174 * @param string $additionalclasses additional classes to add to the main <div> tag (usually 1175 * depend on the course position in list - first/last/even/odd) 1176 * @return string 1177 */ 1178 protected function coursecat_coursebox(coursecat_helper $chelper, $course, $additionalclasses = '') { 1179 global $CFG; 1180 if (!isset($this->strings->summary)) { 1181 $this->strings->summary = get_string('summary'); 1182 } 1183 if ($chelper->get_show_courses() <= self::COURSECAT_SHOW_COURSES_COUNT) { 1184 return ''; 1185 } 1186 if ($course instanceof stdClass) { 1187 require_once($CFG->libdir. '/coursecatlib.php'); 1188 $course = new course_in_list($course); 1189 } 1190 $content = ''; 1191 $classes = trim('coursebox clearfix '. $additionalclasses); 1192 if ($chelper->get_show_courses() >= self::COURSECAT_SHOW_COURSES_EXPANDED) { 1193 $nametag = 'h3'; 1194 } else { 1195 $classes .= ' collapsed'; 1196 $nametag = 'div'; 1197 } 1198 1199 // .coursebox 1200 $content .= html_writer::start_tag('div', array( 1201 'class' => $classes, 1202 'data-courseid' => $course->id, 1203 'data-type' => self::COURSECAT_TYPE_COURSE, 1204 )); 1205 1206 $content .= html_writer::start_tag('div', array('class' => 'info')); 1207 1208 // course name 1209 $coursename = $chelper->get_course_formatted_name($course); 1210 $coursenamelink = html_writer::link(new moodle_url('/course/view.php', array('id' => $course->id)), 1211 $coursename, array('class' => $course->visible ? '' : 'dimmed')); 1212 $content .= html_writer::tag($nametag, $coursenamelink, array('class' => 'coursename')); 1213 // If we display course in collapsed form but the course has summary or course contacts, display the link to the info page. 1214 $content .= html_writer::start_tag('div', array('class' => 'moreinfo')); 1215 if ($chelper->get_show_courses() < self::COURSECAT_SHOW_COURSES_EXPANDED) { 1216 if ($course->has_summary() || $course->has_course_contacts() || $course->has_course_overviewfiles()) { 1217 $url = new moodle_url('/course/info.php', array('id' => $course->id)); 1218 $image = html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/info'), 1219 'alt' => $this->strings->summary)); 1220 $content .= html_writer::link($url, $image, array('title' => $this->strings->summary)); 1221 // Make sure JS file to expand course content is included. 1222 $this->coursecat_include_js(); 1223 } 1224 } 1225 $content .= html_writer::end_tag('div'); // .moreinfo 1226 1227 // print enrolmenticons 1228 if ($icons = enrol_get_course_info_icons($course)) { 1229 $content .= html_writer::start_tag('div', array('class' => 'enrolmenticons')); 1230 foreach ($icons as $pix_icon) { 1231 $content .= $this->render($pix_icon); 1232 } 1233 $content .= html_writer::end_tag('div'); // .enrolmenticons 1234 } 1235 1236 $content .= html_writer::end_tag('div'); // .info 1237 1238 $content .= html_writer::start_tag('div', array('class' => 'content')); 1239 $content .= $this->coursecat_coursebox_content($chelper, $course); 1240 $content .= html_writer::end_tag('div'); // .content 1241 1242 $content .= html_writer::end_tag('div'); // .coursebox 1243 return $content; 1244 } 1245 1246 /** 1247 * Returns HTML to display course content (summary, course contacts and optionally category name) 1248 * 1249 * This method is called from coursecat_coursebox() and may be re-used in AJAX 1250 * 1251 * @param coursecat_helper $chelper various display options 1252 * @param stdClass|course_in_list $course 1253 * @return string 1254 */ 1255 protected function coursecat_coursebox_content(coursecat_helper $chelper, $course) { 1256 global $CFG; 1257 if ($chelper->get_show_courses() < self::COURSECAT_SHOW_COURSES_EXPANDED) { 1258 return ''; 1259 } 1260 if ($course instanceof stdClass) { 1261 require_once($CFG->libdir. '/coursecatlib.php'); 1262 $course = new course_in_list($course); 1263 } 1264 $content = ''; 1265 1266 // display course summary 1267 if ($course->has_summary()) { 1268 $content .= html_writer::start_tag('div', array('class' => 'summary')); 1269 $content .= $chelper->get_course_formatted_summary($course, 1270 array('overflowdiv' => true, 'noclean' => true, 'para' => false)); 1271 $content .= html_writer::end_tag('div'); // .summary 1272 } 1273 1274 // display course overview files 1275 $contentimages = $contentfiles = ''; 1276 foreach ($course->get_course_overviewfiles() as $file) { 1277 $isimage = $file->is_valid_image(); 1278 $url = file_encode_url("$CFG->wwwroot/pluginfile.php", 1279 '/'. $file->get_contextid(). '/'. $file->get_component(). '/'. 1280 $file->get_filearea(). $file->get_filepath(). $file->get_filename(), !$isimage); 1281 if ($isimage) { 1282 $contentimages .= html_writer::tag('div', 1283 html_writer::empty_tag('img', array('src' => $url)), 1284 array('class' => 'courseimage')); 1285 } else { 1286 $image = $this->output->pix_icon(file_file_icon($file, 24), $file->get_filename(), 'moodle'); 1287 $filename = html_writer::tag('span', $image, array('class' => 'fp-icon')). 1288 html_writer::tag('span', $file->get_filename(), array('class' => 'fp-filename')); 1289 $contentfiles .= html_writer::tag('span', 1290 html_writer::link($url, $filename), 1291 array('class' => 'coursefile fp-filename-icon')); 1292 } 1293 } 1294 $content .= $contentimages. $contentfiles; 1295 1296 // display course contacts. See course_in_list::get_course_contacts() 1297 if ($course->has_course_contacts()) { 1298 $content .= html_writer::start_tag('ul', array('class' => 'teachers')); 1299 foreach ($course->get_course_contacts() as $userid => $coursecontact) { 1300 $name = $coursecontact['rolename'].': '. 1301 html_writer::link(new moodle_url('/user/view.php', 1302 array('id' => $userid, 'course' => SITEID)), 1303 $coursecontact['username']); 1304 $content .= html_writer::tag('li', $name); 1305 } 1306 $content .= html_writer::end_tag('ul'); // .teachers 1307 } 1308 1309 // display course category if necessary (for example in search results) 1310 if ($chelper->get_show_courses() == self::COURSECAT_SHOW_COURSES_EXPANDED_WITH_CAT) { 1311 require_once($CFG->libdir. '/coursecatlib.php'); 1312 if ($cat = coursecat::get($course->category, IGNORE_MISSING)) { 1313 $content .= html_writer::start_tag('div', array('class' => 'coursecat')); 1314 $content .= get_string('category').': '. 1315 html_writer::link(new moodle_url('/course/index.php', array('categoryid' => $cat->id)), 1316 $cat->get_formatted_name(), array('class' => $cat->visible ? '' : 'dimmed')); 1317 $content .= html_writer::end_tag('div'); // .coursecat 1318 } 1319 } 1320 1321 return $content; 1322 } 1323 1324 /** 1325 * Renders the list of courses 1326 * 1327 * This is internal function, please use {@link core_course_renderer::courses_list()} or another public 1328 * method from outside of the class 1329 * 1330 * If list of courses is specified in $courses; the argument $chelper is only used 1331 * to retrieve display options and attributes, only methods get_show_courses(), 1332 * get_courses_display_option() and get_and_erase_attributes() are called. 1333 * 1334 * @param coursecat_helper $chelper various display options 1335 * @param array $courses the list of courses to display 1336 * @param int|null $totalcount total number of courses (affects display mode if it is AUTO or pagination if applicable), 1337 * defaulted to count($courses) 1338 * @return string 1339 */ 1340 protected function coursecat_courses(coursecat_helper $chelper, $courses, $totalcount = null) { 1341 global $CFG; 1342 if ($totalcount === null) { 1343 $totalcount = count($courses); 1344 } 1345 if (!$totalcount) { 1346 // Courses count is cached during courses retrieval. 1347 return ''; 1348 } 1349 1350 if ($chelper->get_show_courses() == self::COURSECAT_SHOW_COURSES_AUTO) { 1351 // In 'auto' course display mode we analyse if number of courses is more or less than $CFG->courseswithsummarieslimit 1352 if ($totalcount <= $CFG->courseswithsummarieslimit) { 1353 $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED); 1354 } else { 1355 $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_COLLAPSED); 1356 } 1357 } 1358 1359 // prepare content of paging bar if it is needed 1360 $paginationurl = $chelper->get_courses_display_option('paginationurl'); 1361 $paginationallowall = $chelper->get_courses_display_option('paginationallowall'); 1362 if ($totalcount > count($courses)) { 1363 // there are more results that can fit on one page 1364 if ($paginationurl) { 1365 // the option paginationurl was specified, display pagingbar 1366 $perpage = $chelper->get_courses_display_option('limit', $CFG->coursesperpage); 1367 $page = $chelper->get_courses_display_option('offset') / $perpage; 1368 $pagingbar = $this->paging_bar($totalcount, $page, $perpage, 1369 $paginationurl->out(false, array('perpage' => $perpage))); 1370 if ($paginationallowall) { 1371 $pagingbar .= html_writer::tag('div', html_writer::link($paginationurl->out(false, array('perpage' => 'all')), 1372 get_string('showall', '', $totalcount)), array('class' => 'paging paging-showall')); 1373 } 1374 } else if ($viewmoreurl = $chelper->get_courses_display_option('viewmoreurl')) { 1375 // the option for 'View more' link was specified, display more link 1376 $viewmoretext = $chelper->get_courses_display_option('viewmoretext', new lang_string('viewmore')); 1377 $morelink = html_writer::tag('div', html_writer::link($viewmoreurl, $viewmoretext), 1378 array('class' => 'paging paging-morelink')); 1379 } 1380 } else if (($totalcount > $CFG->coursesperpage) && $paginationurl && $paginationallowall) { 1381 // there are more than one page of results and we are in 'view all' mode, suggest to go back to paginated view mode 1382 $pagingbar = html_writer::tag('div', html_writer::link($paginationurl->out(false, array('perpage' => $CFG->coursesperpage)), 1383 get_string('showperpage', '', $CFG->coursesperpage)), array('class' => 'paging paging-showperpage')); 1384 } 1385 1386 // display list of courses 1387 $attributes = $chelper->get_and_erase_attributes('courses'); 1388 $content = html_writer::start_tag('div', $attributes); 1389 1390 if (!empty($pagingbar)) { 1391 $content .= $pagingbar; 1392 } 1393 1394 $coursecount = 0; 1395 foreach ($courses as $course) { 1396 $coursecount ++; 1397 $classes = ($coursecount%2) ? 'odd' : 'even'; 1398 if ($coursecount == 1) { 1399 $classes .= ' first'; 1400 } 1401 if ($coursecount >= count($courses)) { 1402 $classes .= ' last'; 1403 } 1404 $content .= $this->coursecat_coursebox($chelper, $course, $classes); 1405 } 1406 1407 if (!empty($pagingbar)) { 1408 $content .= $pagingbar; 1409 } 1410 if (!empty($morelink)) { 1411 $content .= $morelink; 1412 } 1413 1414 $content .= html_writer::end_tag('div'); // .courses 1415 return $content; 1416 } 1417 1418 /** 1419 * Renders the list of subcategories in a category 1420 * 1421 * @param coursecat_helper $chelper various display options 1422 * @param coursecat $coursecat 1423 * @param int $depth depth of the category in the current tree 1424 * @return string 1425 */ 1426 protected function coursecat_subcategories(coursecat_helper $chelper, $coursecat, $depth) { 1427 global $CFG; 1428 $subcategories = array(); 1429 if (!$chelper->get_categories_display_option('nodisplay')) { 1430 $subcategories = $coursecat->get_children($chelper->get_categories_display_options()); 1431 } 1432 $totalcount = $coursecat->get_children_count(); 1433 if (!$totalcount) { 1434 // Note that we call get_child_categories_count() AFTER get_child_categories() to avoid extra DB requests. 1435 // Categories count is cached during children categories retrieval. 1436 return ''; 1437 } 1438 1439 // prepare content of paging bar or more link if it is needed 1440 $paginationurl = $chelper->get_categories_display_option('paginationurl'); 1441 $paginationallowall = $chelper->get_categories_display_option('paginationallowall'); 1442 if ($totalcount > count($subcategories)) { 1443 if ($paginationurl) { 1444 // the option 'paginationurl was specified, display pagingbar 1445 $perpage = $chelper->get_categories_display_option('limit', $CFG->coursesperpage); 1446 $page = $chelper->get_categories_display_option('offset') / $perpage; 1447 $pagingbar = $this->paging_bar($totalcount, $page, $perpage, 1448 $paginationurl->out(false, array('perpage' => $perpage))); 1449 if ($paginationallowall) { 1450 $pagingbar .= html_writer::tag('div', html_writer::link($paginationurl->out(false, array('perpage' => 'all')), 1451 get_string('showall', '', $totalcount)), array('class' => 'paging paging-showall')); 1452 } 1453 } else if ($viewmoreurl = $chelper->get_categories_display_option('viewmoreurl')) { 1454 // the option 'viewmoreurl' was specified, display more link (if it is link to category view page, add category id) 1455 if ($viewmoreurl->compare(new moodle_url('/course/index.php'), URL_MATCH_BASE)) { 1456 $viewmoreurl->param('categoryid', $coursecat->id); 1457 } 1458 $viewmoretext = $chelper->get_categories_display_option('viewmoretext', new lang_string('viewmore')); 1459 $morelink = html_writer::tag('div', html_writer::link($viewmoreurl, $viewmoretext), 1460 array('class' => 'paging paging-morelink')); 1461 } 1462 } else if (($totalcount > $CFG->coursesperpage) && $paginationurl && $paginationallowall) { 1463 // there are more than one page of results and we are in 'view all' mode, suggest to go back to paginated view mode 1464 $pagingbar = html_writer::tag('div', html_writer::link($paginationurl->out(false, array('perpage' => $CFG->coursesperpage)), 1465 get_string('showperpage', '', $CFG->coursesperpage)), array('class' => 'paging paging-showperpage')); 1466 } 1467 1468 // display list of subcategories 1469 $content = html_writer::start_tag('div', array('class' => 'subcategories')); 1470 1471 if (!empty($pagingbar)) { 1472 $content .= $pagingbar; 1473 } 1474 1475 foreach ($subcategories as $subcategory) { 1476 $content .= $this->coursecat_category($chelper, $subcategory, $depth + 1); 1477 } 1478 1479 if (!empty($pagingbar)) { 1480 $content .= $pagingbar; 1481 } 1482 if (!empty($morelink)) { 1483 $content .= $morelink; 1484 } 1485 1486 $content .= html_writer::end_tag('div'); 1487 return $content; 1488 } 1489 1490 /** 1491 * Make sure that javascript file for AJAX expanding of courses and categories content is included 1492 */ 1493 protected function coursecat_include_js() { 1494 if (!$this->page->requires->should_create_one_time_item_now('core_course_categoryexpanderjsinit')) { 1495 return; 1496 } 1497 1498 // We must only load this module once. 1499 $this->page->requires->yui_module('moodle-course-categoryexpander', 1500 'Y.Moodle.course.categoryexpander.init'); 1501 } 1502 1503 /** 1504 * Returns HTML to display the subcategories and courses in the given category 1505 * 1506 * This method is re-used by AJAX to expand content of not loaded category 1507 * 1508 * @param coursecat_helper $chelper various display options 1509 * @param coursecat $coursecat 1510 * @param int $depth depth of the category in the current tree 1511 * @return string 1512 */ 1513 protected function coursecat_category_content(coursecat_helper $chelper, $coursecat, $depth) { 1514 $content = ''; 1515 // Subcategories 1516 $content .= $this->coursecat_subcategories($chelper, $coursecat, $depth); 1517 1518 // AUTO show courses: Courses will be shown expanded if this is not nested category, 1519 // and number of courses no bigger than $CFG->courseswithsummarieslimit. 1520 $showcoursesauto = $chelper->get_show_courses() == self::COURSECAT_SHOW_COURSES_AUTO; 1521 if ($showcoursesauto && $depth) { 1522 // this is definitely collapsed mode 1523 $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_COLLAPSED); 1524 } 1525 1526 // Courses 1527 if ($chelper->get_show_courses() > core_course_renderer::COURSECAT_SHOW_COURSES_COUNT) { 1528 $courses = array(); 1529 if (!$chelper->get_courses_display_option('nodisplay')) { 1530 $courses = $coursecat->get_courses($chelper->get_courses_display_options()); 1531 } 1532 if ($viewmoreurl = $chelper->get_courses_display_option('viewmoreurl')) { 1533 // the option for 'View more' link was specified, display more link (if it is link to category view page, add category id) 1534 if ($viewmoreurl->compare(new moodle_url('/course/index.php'), URL_MATCH_BASE)) { 1535 $chelper->set_courses_display_option('viewmoreurl', new moodle_url($viewmoreurl, array('categoryid' => $coursecat->id))); 1536 } 1537 } 1538 $content .= $this->coursecat_courses($chelper, $courses, $coursecat->get_courses_count()); 1539 } 1540 1541 if ($showcoursesauto) { 1542 // restore the show_courses back to AUTO 1543 $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_AUTO); 1544 } 1545 1546 return $content; 1547 } 1548 1549 /** 1550 * Returns HTML to display a course category as a part of a tree 1551 * 1552 * This is an internal function, to display a particular category and all its contents 1553 * use {@link core_course_renderer::course_category()} 1554 * 1555 * @param coursecat_helper $chelper various display options 1556 * @param coursecat $coursecat 1557 * @param int $depth depth of this category in the current tree 1558 * @return string 1559 */ 1560 protected function coursecat_category(coursecat_helper $chelper, $coursecat, $depth) { 1561 // open category tag 1562 $classes = array('category'); 1563 if (empty($coursecat->visible)) { 1564 $classes[] = 'dimmed_category'; 1565 } 1566 if ($chelper->get_subcat_depth() > 0 && $depth >= $chelper->get_subcat_depth()) { 1567 // do not load content 1568 $categorycontent = ''; 1569 $classes[] = 'notloaded'; 1570 if ($coursecat->get_children_count() || 1571 ($chelper->get_show_courses() >= self::COURSECAT_SHOW_COURSES_COLLAPSED && $coursecat->get_courses_count())) { 1572 $classes[] = 'with_children'; 1573 $classes[] = 'collapsed'; 1574 } 1575 } else { 1576 // load category content 1577 $categorycontent = $this->coursecat_category_content($chelper, $coursecat, $depth); 1578 $classes[] = 'loaded'; 1579 if (!empty($categorycontent)) { 1580 $classes[] = 'with_children'; 1581 } 1582 } 1583 1584 // Make sure JS file to expand category content is included. 1585 $this->coursecat_include_js(); 1586 1587 $content = html_writer::start_tag('div', array( 1588 'class' => join(' ', $classes), 1589 'data-categoryid' => $coursecat->id, 1590 'data-depth' => $depth, 1591 'data-showcourses' => $chelper->get_show_courses(), 1592 'data-type' => self::COURSECAT_TYPE_CATEGORY, 1593 )); 1594 1595 // category name 1596 $categoryname = $coursecat->get_formatted_name(); 1597 $categoryname = html_writer::link(new moodle_url('/course/index.php', 1598 array('categoryid' => $coursecat->id)), 1599 $categoryname); 1600 if ($chelper->get_show_courses() == self::COURSECAT_SHOW_COURSES_COUNT 1601 && ($coursescount = $coursecat->get_courses_count())) { 1602 $categoryname .= html_writer::tag('span', ' ('. $coursescount.')', 1603 array('title' => get_string('numberofcourses'), 'class' => 'numberofcourse')); 1604 } 1605 $content .= html_writer::start_tag('div', array('class' => 'info')); 1606 1607 $content .= html_writer::tag(($depth > 1) ? 'h4' : 'h3', $categoryname, array('class' => 'categoryname')); 1608 $content .= html_writer::end_tag('div'); // .info 1609 1610 // add category content to the output 1611 $content .= html_writer::tag('div', $categorycontent, array('class' => 'content')); 1612 1613 $content .= html_writer::end_tag('div'); // .category 1614 1615 // Return the course category tree HTML 1616 return $content; 1617 } 1618 1619 /** 1620 * Returns HTML to display a tree of subcategories and courses in the given category 1621 * 1622 * @param coursecat_helper $chelper various display options 1623 * @param coursecat $coursecat top category (this category's name and description will NOT be added to the tree) 1624 * @return string 1625 */ 1626 protected function coursecat_tree(coursecat_helper $chelper, $coursecat) { 1627 $categorycontent = $this->coursecat_category_content($chelper, $coursecat, 0); 1628 if (empty($categorycontent)) { 1629 return ''; 1630 } 1631 1632 // Start content generation 1633 $content = ''; 1634 $attributes = $chelper->get_and_erase_attributes('course_category_tree clearfix'); 1635 $content .= html_writer::start_tag('div', $attributes); 1636 1637 if ($coursecat->get_children_count()) { 1638 $classes = array( 1639 'collapseexpand', 1640 'collapse-all', 1641 ); 1642 if ($chelper->get_subcat_depth() == 1) { 1643 $classes[] = 'disabled'; 1644 } 1645 // Only show the collapse/expand if there are children to expand. 1646 $content .= html_writer::start_tag('div', array('class' => 'collapsible-actions')); 1647 $content .= html_writer::link('#', get_string('collapseall'), 1648 array('class' => implode(' ', $classes))); 1649 $content .= html_writer::end_tag('div'); 1650 $this->page->requires->strings_for_js(array('collapseall', 'expandall'), 'moodle'); 1651 } 1652 1653 $content .= html_writer::tag('div', $categorycontent, array('class' => 'content')); 1654 1655 $content .= html_writer::end_tag('div'); // .course_category_tree 1656 1657 return $content; 1658 } 1659 1660 /** 1661 * Renders HTML to display particular course category - list of it's subcategories and courses 1662 * 1663 * Invoked from /course/index.php 1664 * 1665 * @param int|stdClass|coursecat $category 1666 */ 1667 public function course_category($category) { 1668 global $CFG; 1669 require_once($CFG->libdir. '/coursecatlib.php'); 1670 $coursecat = coursecat::get(is_object($category) ? $category->id : $category); 1671 $site = get_site(); 1672 $output = ''; 1673 1674 if (can_edit_in_category($category)) { 1675 // Add 'Manage' button if user has permissions to edit this category. 1676 $managebutton = $this->single_button(new moodle_url('/course/management.php'), get_string('managecourses'), 'get'); 1677 $this->page->set_button($managebutton); 1678 } 1679 if (!$coursecat->id) { 1680 if (coursecat::count_all() == 1) { 1681 // There exists only one category in the system, do not display link to it 1682 $coursecat = coursecat::get_default(); 1683 $strfulllistofcourses = get_string('fulllistofcourses'); 1684 $this->page->set_title("$site->shortname: $strfulllistofcourses"); 1685 } else { 1686 $strcategories = get_string('categories'); 1687 $this->page->set_title("$site->shortname: $strcategories"); 1688 } 1689 } else { 1690 $this->page->set_title("$site->shortname: ". $coursecat->get_formatted_name()); 1691 1692 // Print the category selector 1693 $output .= html_writer::start_tag('div', array('class' => 'categorypicker')); 1694 $select = new single_select(new moodle_url('/course/index.php'), 'categoryid', 1695 coursecat::make_categories_list(), $coursecat->id, null, 'switchcategory'); 1696 $select->set_label(get_string('categories').':'); 1697 $output .= $this->render($select); 1698 $output .= html_writer::end_tag('div'); // .categorypicker 1699 } 1700 1701 // Print current category description 1702 $chelper = new coursecat_helper(); 1703 if ($description = $chelper->get_category_formatted_description($coursecat)) { 1704 $output .= $this->box($description, array('class' => 'generalbox info')); 1705 } 1706 1707 // Prepare parameters for courses and categories lists in the tree 1708 $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_AUTO) 1709 ->set_attributes(array('class' => 'category-browse category-browse-'.$coursecat->id)); 1710 1711 $coursedisplayoptions = array(); 1712 $catdisplayoptions = array(); 1713 $browse = optional_param('browse', null, PARAM_ALPHA); 1714 $perpage = optional_param('perpage', $CFG->coursesperpage, PARAM_INT); 1715 $page = optional_param('page', 0, PARAM_INT); 1716 $baseurl = new moodle_url('/course/index.php'); 1717 if ($coursecat->id) { 1718 $baseurl->param('categoryid', $coursecat->id); 1719 } 1720 if ($perpage != $CFG->coursesperpage) { 1721 $baseurl->param('perpage', $perpage); 1722 } 1723 $coursedisplayoptions['limit'] = $perpage; 1724 $catdisplayoptions['limit'] = $perpage; 1725 if ($browse === 'courses' || !$coursecat->has_children()) { 1726 $coursedisplayoptions['offset'] = $page * $perpage; 1727 $coursedisplayoptions['paginationurl'] = new moodle_url($baseurl, array('browse' => 'courses')); 1728 $catdisplayoptions['nodisplay'] = true; 1729 $catdisplayoptions['viewmoreurl'] = new moodle_url($baseurl, array('browse' => 'categories')); 1730 $catdisplayoptions['viewmoretext'] = new lang_string('viewallsubcategories'); 1731 } else if ($browse === 'categories' || !$coursecat->has_courses()) { 1732 $coursedisplayoptions['nodisplay'] = true; 1733 $catdisplayoptions['offset'] = $page * $perpage; 1734 $catdisplayoptions['paginationurl'] = new moodle_url($baseurl, array('browse' => 'categories')); 1735 $coursedisplayoptions['viewmoreurl'] = new moodle_url($baseurl, array('browse' => 'courses')); 1736 $coursedisplayoptions['viewmoretext'] = new lang_string('viewallcourses'); 1737 } else { 1738 // we have a category that has both subcategories and courses, display pagination separately 1739 $coursedisplayoptions['viewmoreurl'] = new moodle_url($baseurl, array('browse' => 'courses', 'page' => 1)); 1740 $catdisplayoptions['viewmoreurl'] = new moodle_url($baseurl, array('browse' => 'categories', 'page' => 1)); 1741 } 1742 $chelper->set_courses_display_options($coursedisplayoptions)->set_categories_display_options($catdisplayoptions); 1743 // Add course search form. 1744 $output .= $this->course_search_form(); 1745 1746 // Display course category tree. 1747 $output .= $this->coursecat_tree($chelper, $coursecat); 1748 1749 // Add action buttons 1750 $output .= $this->container_start('buttons'); 1751 $context = get_category_or_system_context($coursecat->id); 1752 if (has_capability('moodle/course:create', $context)) { 1753 // Print link to create a new course, for the 1st available category. 1754 if ($coursecat->id) { 1755 $url = new moodle_url('/course/edit.php', array('category' => $coursecat->id, 'returnto' => 'category')); 1756 } else { 1757 $url = new moodle_url('/course/edit.php', array('category' => $CFG->defaultrequestcategory, 'returnto' => 'topcat')); 1758 } 1759 $output .= $this->single_button($url, get_string('addnewcourse'), 'get'); 1760 } 1761 ob_start(); 1762 if (coursecat::count_all() == 1) { 1763 print_course_request_buttons(context_system::instance()); 1764 } else { 1765 print_course_request_buttons($context); 1766 } 1767 $output .= ob_get_contents(); 1768 ob_end_clean(); 1769 $output .= $this->container_end(); 1770 1771 return $output; 1772 } 1773 1774 /** 1775 * Serves requests to /course/category.ajax.php 1776 * 1777 * In this renderer implementation it may expand the category content or 1778 * course content. 1779 * 1780 * @return string 1781 * @throws coding_exception 1782 */ 1783 public function coursecat_ajax() { 1784 global $DB, $CFG; 1785 require_once($CFG->libdir. '/coursecatlib.php'); 1786 1787 $type = required_param('type', PARAM_INT); 1788 1789 if ($type === self::COURSECAT_TYPE_CATEGORY) { 1790 // This is a request for a category list of some kind. 1791 $categoryid = required_param('categoryid', PARAM_INT); 1792 $showcourses = required_param('showcourses', PARAM_INT); 1793 $depth = required_param('depth', PARAM_INT); 1794 1795 $category = coursecat::get($categoryid); 1796 1797 $chelper = new coursecat_helper(); 1798 $baseurl = new moodle_url('/course/index.php', array('categoryid' => $categoryid)); 1799 $coursedisplayoptions = array( 1800 'limit' => $CFG->coursesperpage, 1801 'viewmoreurl' => new moodle_url($baseurl, array('browse' => 'courses', 'page' => 1)) 1802 ); 1803 $catdisplayoptions = array( 1804 'limit' => $CFG->coursesperpage, 1805 'viewmoreurl' => new moodle_url($baseurl, array('browse' => 'categories', 'page' => 1)) 1806 ); 1807 $chelper->set_show_courses($showcourses)-> 1808 set_courses_display_options($coursedisplayoptions)-> 1809 set_categories_display_options($catdisplayoptions); 1810 1811 return $this->coursecat_category_content($chelper, $category, $depth); 1812 } else if ($type === self::COURSECAT_TYPE_COURSE) { 1813 // This is a request for the course information. 1814 $courseid = required_param('courseid', PARAM_INT); 1815 1816 $course = $DB->get_record('course', array('id' => $courseid), '*', MUST_EXIST); 1817 1818 $chelper = new coursecat_helper(); 1819 $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED); 1820 return $this->coursecat_coursebox_content($chelper, $course); 1821 } else { 1822 throw new coding_exception('Invalid request type'); 1823 } 1824 } 1825 1826 /** 1827 * Renders html to display search result page 1828 * 1829 * @param array $searchcriteria may contain elements: search, blocklist, modulelist, tagid 1830 * @return string 1831 */ 1832 public function search_courses($searchcriteria) { 1833 global $CFG; 1834 $content = ''; 1835 if (!empty($searchcriteria)) { 1836 // print search results 1837 require_once($CFG->libdir. '/coursecatlib.php'); 1838 1839 $displayoptions = array('sort' => array('displayname' => 1)); 1840 // take the current page and number of results per page from query 1841 $perpage = optional_param('perpage', 0, PARAM_RAW); 1842 if ($perpage !== 'all') { 1843 $displayoptions['limit'] = ((int)$perpage <= 0) ? $CFG->coursesperpage : (int)$perpage; 1844 $page = optional_param('page', 0, PARAM_INT); 1845 $displayoptions['offset'] = $displayoptions['limit'] * $page; 1846 } 1847 // options 'paginationurl' and 'paginationallowall' are only used in method coursecat_courses() 1848 $displayoptions['paginationurl'] = new moodle_url('/course/search.php', $searchcriteria); 1849 $displayoptions['paginationallowall'] = true; // allow adding link 'View all' 1850 1851 $class = 'course-search-result'; 1852 foreach ($searchcriteria as $key => $value) { 1853 if (!empty($value)) { 1854 $class .= ' course-search-result-'. $key; 1855 } 1856 } 1857 $chelper = new coursecat_helper(); 1858 $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED_WITH_CAT)-> 1859 set_courses_display_options($displayoptions)-> 1860 set_search_criteria($searchcriteria)-> 1861 set_attributes(array('class' => $class)); 1862 1863 $courses = coursecat::search_courses($searchcriteria, $chelper->get_courses_display_options()); 1864 $totalcount = coursecat::search_courses_count($searchcriteria); 1865 $courseslist = $this->coursecat_courses($chelper, $courses, $totalcount); 1866 1867 if (!$totalcount) { 1868 if (!empty($searchcriteria['search'])) { 1869 $content .= $this->heading(get_string('nocoursesfound', '', $searchcriteria['search'])); 1870 } else { 1871 $content .= $this->heading(get_string('novalidcourses')); 1872 } 1873 } else { 1874 $content .= $this->heading(get_string('searchresults'). ": $totalcount"); 1875 $content .= $courseslist; 1876 } 1877 1878 if (!empty($searchcriteria['search'])) { 1879 // print search form only if there was a search by search string, otherwise it is confusing 1880 $content .= $this->box_start('generalbox mdl-align'); 1881 $content .= $this->course_search_form($searchcriteria['search']); 1882 $content .= $this->box_end(); 1883 } 1884 } else { 1885 // just print search form 1886 $content .= $this->box_start('generalbox mdl-align'); 1887 $content .= $this->course_search_form(); 1888 $content .= html_writer::tag('div', get_string("searchhelp"), array('class' => 'searchhelp')); 1889 $content .= $this->box_end(); 1890 } 1891 return $content; 1892 } 1893 1894 /** 1895 * Renders html to print list of courses tagged with particular tag 1896 * 1897 * @param int $tagid id of the tag 1898 * @return string empty string if no courses are marked with this tag or rendered list of courses 1899 */ 1900 public function tagged_courses($tagid) { 1901 global $CFG; 1902 require_once($CFG->libdir. '/coursecatlib.php'); 1903 $displayoptions = array('limit' => $CFG->coursesperpage); 1904 $displayoptions['viewmoreurl'] = new moodle_url('/course/search.php', 1905 array('tagid' => $tagid, 'page' => 1, 'perpage' => $CFG->coursesperpage)); 1906 $displayoptions['viewmoretext'] = new lang_string('findmorecourses'); 1907 $chelper = new coursecat_helper(); 1908 $searchcriteria = array('tagid' => $tagid); 1909 $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED_WITH_CAT)-> 1910 set_search_criteria(array('tagid' => $tagid))-> 1911 set_courses_display_options($displayoptions)-> 1912 set_attributes(array('class' => 'course-search-result course-search-result-tagid')); 1913 // (we set the same css class as in search results by tagid) 1914 $courses = coursecat::search_courses($searchcriteria, $chelper->get_courses_display_options()); 1915 $totalcount = coursecat::search_courses_count($searchcriteria); 1916 $content = $this->coursecat_courses($chelper, $courses, $totalcount); 1917 if ($totalcount) { 1918 require_once $CFG->dirroot.'/tag/lib.php'; 1919 $heading = get_string('courses') . ' ' . get_string('taggedwith', 'tag', tag_get_name($tagid)) .': '. $totalcount; 1920 return $this->heading($heading, 3). $content; 1921 } 1922 return ''; 1923 } 1924 1925 /** 1926 * Returns HTML to display one remote course 1927 * 1928 * @param stdClass $course remote course information, contains properties: 1929 id, remoteid, shortname, fullname, hostid, summary, summaryformat, cat_name, hostname 1930 * @return string 1931 */ 1932 protected function frontpage_remote_course(stdClass $course) { 1933 $url = new moodle_url('/auth/mnet/jump.php', array( 1934 'hostid' => $course->hostid, 1935 'wantsurl' => '/course/view.php?id='. $course->remoteid 1936 )); 1937 1938 $output = ''; 1939 $output .= html_writer::start_tag('div', array('class' => 'coursebox remotecoursebox clearfix')); 1940 $output .= html_writer::start_tag('div', array('class' => 'info')); 1941 $output .= html_writer::start_tag('h3', array('class' => 'name')); 1942 $output .= html_writer::link($url, format_string($course->fullname), array('title' => get_string('entercourse'))); 1943 $output .= html_writer::end_tag('h3'); // .name 1944 $output .= html_writer::tag('div', '', array('class' => 'moreinfo')); 1945 $output .= html_writer::end_tag('div'); // .info 1946 $output .= html_writer::start_tag('div', array('class' => 'content')); 1947 $output .= html_writer::start_tag('div', array('class' => 'summary')); 1948 $options = new stdClass(); 1949 $options->noclean = true; 1950 $options->para = false; 1951 $options->overflowdiv = true; 1952 $output .= format_text($course->summary, $course->summaryformat, $options); 1953 $output .= html_writer::end_tag('div'); // .summary 1954 $addinfo = format_string($course->hostname) . ' : ' 1955 . format_string($course->cat_name) . ' : ' 1956 . format_string($course->shortname); 1957 $output .= html_writer::tag('div', $addinfo, array('class' => 'remotecourseinfo')); 1958 $output .= html_writer::end_tag('div'); // .content 1959 $output .= html_writer::end_tag('div'); // .coursebox 1960 return $output; 1961 } 1962 1963 /** 1964 * Returns HTML to display one remote host 1965 * 1966 * @param array $host host information, contains properties: name, url, count 1967 * @return string 1968 */ 1969 protected function frontpage_remote_host($host) { 1970 $output = ''; 1971 $output .= html_writer::start_tag('div', array('class' => 'coursebox remotehost clearfix')); 1972 $output .= html_writer::start_tag('div', array('class' => 'info')); 1973 $output .= html_writer::start_tag('h3', array('class' => 'name')); 1974 $output .= html_writer::link($host['url'], s($host['name']), array('title' => s($host['name']))); 1975 $output .= html_writer::end_tag('h3'); // .name 1976 $output .= html_writer::tag('div', '', array('class' => 'moreinfo')); 1977 $output .= html_writer::end_tag('div'); // .info 1978 $output .= html_writer::start_tag('div', array('class' => 'content')); 1979 $output .= html_writer::start_tag('div', array('class' => 'summary')); 1980 $output .= $host['count'] . ' ' . get_string('courses'); 1981 $output .= html_writer::end_tag('div'); // .content 1982 $output .= html_writer::end_tag('div'); // .coursebox 1983 return $output; 1984 } 1985 1986 /** 1987 * Returns HTML to print list of courses user is enrolled to for the frontpage 1988 * 1989 * Also lists remote courses or remote hosts if MNET authorisation is used 1990 * 1991 * @return string 1992 */ 1993 public function frontpage_my_courses() { 1994 global $USER, $CFG, $DB; 1995 1996 if (!isloggedin() or isguestuser()) { 1997 return ''; 1998 } 1999 2000 $output = ''; 2001 if (!empty($CFG->navsortmycoursessort)) { 2002 // sort courses the same as in navigation menu 2003 $sortorder = 'visible DESC,'. $CFG->navsortmycoursessort.' ASC'; 2004 } else { 2005 $sortorder = 'visible DESC,sortorder ASC'; 2006 } 2007 $courses = enrol_get_my_courses('summary, summaryformat', $sortorder); 2008 $rhosts = array(); 2009 $rcourses = array(); 2010 if (!empty($CFG->mnet_dispatcher_mode) && $CFG->mnet_dispatcher_mode==='strict') { 2011 $rcourses = get_my_remotecourses($USER->id); 2012 $rhosts = get_my_remotehosts(); 2013 } 2014 2015 if (!empty($courses) || !empty($rcourses) || !empty($rhosts)) { 2016 2017 $chelper = new coursecat_helper(); 2018 if (count($courses) > $CFG->frontpagecourselimit) { 2019 // There are more enrolled courses than we can display, display link to 'My courses'. 2020 $totalcount = count($courses); 2021 $courses = array_slice($courses, 0, $CFG->frontpagecourselimit, true); 2022 $chelper->set_courses_display_options(array( 2023 'viewmoreurl' => new moodle_url('/my/'), 2024 'viewmoretext' => new lang_string('mycourses') 2025 )); 2026 } else { 2027 // All enrolled courses are displayed, display link to 'All courses' if there are more courses in system. 2028 $chelper->set_courses_display_options(array( 2029 'viewmoreurl' => new moodle_url('/course/index.php'), 2030 'viewmoretext' => new lang_string('fulllistofcourses') 2031 )); 2032 $totalcount = $DB->count_records('course') - 1; 2033 } 2034 $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED)-> 2035 set_attributes(array('class' => 'frontpage-course-list-enrolled')); 2036 $output .= $this->coursecat_courses($chelper, $courses, $totalcount); 2037 2038 // MNET 2039 if (!empty($rcourses)) { 2040 // at the IDP, we know of all the remote courses 2041 $output .= html_writer::start_tag('div', array('class' => 'courses')); 2042 foreach ($rcourses as $course) { 2043 $output .= $this->frontpage_remote_course($course); 2044 } 2045 $output .= html_writer::end_tag('div'); // .courses 2046 } elseif (!empty($rhosts)) { 2047 // non-IDP, we know of all the remote servers, but not courses 2048 $output .= html_writer::start_tag('div', array('class' => 'courses')); 2049 foreach ($rhosts as $host) { 2050 $output .= $this->frontpage_remote_host($host); 2051 } 2052 $output .= html_writer::end_tag('div'); // .courses 2053 } 2054 } 2055 return $output; 2056 } 2057 2058 /** 2059 * Returns HTML to print list of available courses for the frontpage 2060 * 2061 * @return string 2062 */ 2063 public function frontpage_available_courses() { 2064 global $CFG; 2065 require_once($CFG->libdir. '/coursecatlib.php'); 2066 2067 $chelper = new coursecat_helper(); 2068 $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED)-> 2069 set_courses_display_options(array( 2070 'recursive' => true, 2071 'limit' => $CFG->frontpagecourselimit, 2072 'viewmoreurl' => new moodle_url('/course/index.php'), 2073 'viewmoretext' => new lang_string('fulllistofcourses'))); 2074 2075 $chelper->set_attributes(array('class' => 'frontpage-course-list-all')); 2076 $courses = coursecat::get(0)->get_courses($chelper->get_courses_display_options()); 2077 $totalcount = coursecat::get(0)->get_courses_count($chelper->get_courses_display_options()); 2078 if (!$totalcount && !$this->page->user_is_editing() && has_capability('moodle/course:create', context_system::instance())) { 2079 // Print link to create a new course, for the 1st available category. 2080 return $this->add_new_course_button(); 2081 } 2082 return $this->coursecat_courses($chelper, $courses, $totalcount); 2083 } 2084 2085 /** 2086 * Returns HTML to the "add new course" button for the page 2087 * 2088 * @return string 2089 */ 2090 public function add_new_course_button() { 2091 global $CFG; 2092 // Print link to create a new course, for the 1st available category. 2093 $output = $this->container_start('buttons'); 2094 $url = new moodle_url('/course/edit.php', array('category' => $CFG->defaultrequestcategory, 'returnto' => 'topcat')); 2095 $output .= $this->single_button($url, get_string('addnewcourse'), 'get'); 2096 $output .= $this->container_end('buttons'); 2097 return $output; 2098 } 2099 2100 /** 2101 * Returns HTML to print tree with course categories and courses for the frontpage 2102 * 2103 * @return string 2104 */ 2105 public function frontpage_combo_list() { 2106 global $CFG; 2107 require_once($CFG->libdir. '/coursecatlib.php'); 2108 $chelper = new coursecat_helper(); 2109 $chelper->set_subcat_depth($CFG->maxcategorydepth)-> 2110 set_categories_display_options(array( 2111 'limit' => $CFG->coursesperpage, 2112 'viewmoreurl' => new moodle_url('/course/index.php', 2113 array('browse' => 'categories', 'page' => 1)) 2114 ))-> 2115 set_courses_display_options(array( 2116 'limit' => $CFG->coursesperpage, 2117 'viewmoreurl' => new moodle_url('/course/index.php', 2118 array('browse' => 'courses', 'page' => 1)) 2119 ))-> 2120 set_attributes(array('class' => 'frontpage-category-combo')); 2121 return $this->coursecat_tree($chelper, coursecat::get(0)); 2122 } 2123 2124 /** 2125 * Returns HTML to print tree of course categories (with number of courses) for the frontpage 2126 * 2127 * @return string 2128 */ 2129 public function frontpage_categories_list() { 2130 global $CFG; 2131 require_once($CFG->libdir. '/coursecatlib.php'); 2132 $chelper = new coursecat_helper(); 2133 $chelper->set_subcat_depth($CFG->maxcategorydepth)-> 2134 set_show_courses(self::COURSECAT_SHOW_COURSES_COUNT)-> 2135 set_categories_display_options(array( 2136 'limit' => $CFG->coursesperpage, 2137 'viewmoreurl' => new moodle_url('/course/index.php', 2138 array('browse' => 'categories', 'page' => 1)) 2139 ))-> 2140 set_attributes(array('class' => 'frontpage-category-names')); 2141 return $this->coursecat_tree($chelper, coursecat::get(0)); 2142 } 2143 } 2144 2145 /** 2146 * Class storing display options and functions to help display course category and/or courses lists 2147 * 2148 * This is a wrapper for coursecat objects that also stores display options 2149 * and functions to retrieve sorted and paginated lists of categories/courses. 2150 * 2151 * If theme overrides methods in core_course_renderers that access this class 2152 * it may as well not use this class at all or extend it. 2153 * 2154 * @package core 2155 * @copyright 2013 Marina Glancy 2156 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later 2157 */ 2158 class coursecat_helper { 2159 /** @var string [none, collapsed, expanded] how (if) display courses list */ 2160 protected $showcourses = 10; /* core_course_renderer::COURSECAT_SHOW_COURSES_COLLAPSED */ 2161 /** @var int depth to expand subcategories in the tree (deeper subcategories will be loaded by AJAX or proceed to category page by clicking on category name) */ 2162 protected $subcatdepth = 1; 2163 /** @var array options to display courses list */ 2164 protected $coursesdisplayoptions = array(); 2165 /** @var array options to display subcategories list */ 2166 protected $categoriesdisplayoptions = array(); 2167 /** @var array additional HTML attributes */ 2168 protected $attributes = array(); 2169 /** @var array search criteria if the list is a search result */ 2170 protected $searchcriteria = null; 2171 2172 /** 2173 * Sets how (if) to show the courses - none, collapsed, expanded, etc. 2174 * 2175 * @param int $showcourses SHOW_COURSES_NONE, SHOW_COURSES_COLLAPSED, SHOW_COURSES_EXPANDED, etc. 2176 * @return coursecat_helper 2177 */ 2178 public function set_show_courses($showcourses) { 2179 $this->showcourses = $showcourses; 2180 // Automatically set the options to preload summary and coursecontacts for coursecat::get_courses() and coursecat::search_courses() 2181 $this->coursesdisplayoptions['summary'] = $showcourses >= core_course_renderer::COURSECAT_SHOW_COURSES_AUTO; 2182 $this->coursesdisplayoptions['coursecontacts'] = $showcourses >= core_course_renderer::COURSECAT_SHOW_COURSES_EXPANDED; 2183 return $this; 2184 } 2185 2186 /** 2187 * Returns how (if) to show the courses - none, collapsed, expanded, etc. 2188 * 2189 * @return int - COURSECAT_SHOW_COURSES_NONE, COURSECAT_SHOW_COURSES_COLLAPSED, COURSECAT_SHOW_COURSES_EXPANDED, etc. 2190 */ 2191 public function get_show_courses() { 2192 return $this->showcourses; 2193 } 2194 2195 /** 2196 * Sets the maximum depth to expand subcategories in the tree 2197 * 2198 * deeper subcategories may be loaded by AJAX or proceed to category page by clicking on category name 2199 * 2200 * @param int $subcatdepth 2201 * @return coursecat_helper 2202 */ 2203 public function set_subcat_depth($subcatdepth) { 2204 $this->subcatdepth = $subcatdepth; 2205 return $this; 2206 } 2207 2208 /** 2209 * Returns the maximum depth to expand subcategories in the tree 2210 * 2211 * deeper subcategories may be loaded by AJAX or proceed to category page by clicking on category name 2212 * 2213 * @return int 2214 */ 2215 public function get_subcat_depth() { 2216 return $this->subcatdepth; 2217 } 2218 2219 /** 2220 * Sets options to display list of courses 2221 * 2222 * Options are later submitted as argument to coursecat::get_courses() and/or coursecat::search_courses() 2223 * 2224 * Options that coursecat::get_courses() accept: 2225 * - recursive - return courses from subcategories as well. Use with care, 2226 * this may be a huge list! 2227 * - summary - preloads fields 'summary' and 'summaryformat' 2228 * - coursecontacts - preloads course contacts 2229 * - isenrolled - preloads indication whether this user is enrolled in the course 2230 * - sort - list of fields to sort. Example 2231 * array('idnumber' => 1, 'shortname' => 1, 'id' => -1) 2232 * will sort by idnumber asc, shortname asc and id desc. 2233 * Default: array('sortorder' => 1) 2234 * Only cached fields may be used for sorting! 2235 * - offset 2236 * - limit - maximum number of children to return, 0 or null for no limit 2237 * 2238 * Options summary and coursecontacts are filled automatically in the set_show_courses() 2239 * 2240 * Also renderer can set here any additional options it wants to pass between renderer functions. 2241 * 2242 * @param array $options 2243 * @return coursecat_helper 2244 */ 2245 public function set_courses_display_options($options) { 2246 $this->coursesdisplayoptions = $options; 2247 $this->set_show_courses($this->showcourses); // this will calculate special display options 2248 return $this; 2249 } 2250 2251 /** 2252 * Sets one option to display list of courses 2253 * 2254 * @see coursecat_helper::set_courses_display_options() 2255 * 2256 * @param string $key 2257 * @param mixed $value 2258 * @return coursecat_helper 2259 */ 2260 public function set_courses_display_option($key, $value) { 2261 $this->coursesdisplayoptions[$key] = $value; 2262 return $this; 2263 } 2264 2265 /** 2266 * Return the specified option to display list of courses 2267 * 2268 * @param string $optionname option name 2269 * @param mixed $defaultvalue default value for option if it is not specified 2270 * @return mixed 2271 */ 2272 public function get_courses_display_option($optionname, $defaultvalue = null) { 2273 if (array_key_exists($optionname, $this->coursesdisplayoptions)) { 2274 return $this->coursesdisplayoptions[$optionname]; 2275 } else { 2276 return $defaultvalue; 2277 } 2278 } 2279 2280 /** 2281 * Returns all options to display the courses 2282 * 2283 * This array is usually passed to {@link coursecat::get_courses()} or 2284 * {@link coursecat::search_courses()} 2285 * 2286 * @return array 2287 */ 2288 public function get_courses_display_options() { 2289 return $this->coursesdisplayoptions; 2290 } 2291 2292 /** 2293 * Sets options to display list of subcategories 2294 * 2295 * Options 'sort', 'offset' and 'limit' are passed to coursecat::get_children(). 2296 * Any other options may be used by renderer functions 2297 * 2298 * @param array $options 2299 * @return coursecat_helper 2300 */ 2301 public function set_categories_display_options($options) { 2302 $this->categoriesdisplayoptions = $options; 2303 return $this; 2304 } 2305 2306 /** 2307 * Return the specified option to display list of subcategories 2308 * 2309 * @param string $optionname option name 2310 * @param mixed $defaultvalue default value for option if it is not specified 2311 * @return mixed 2312 */ 2313 public function get_categories_display_option($optionname, $defaultvalue = null) { 2314 if (array_key_exists($optionname, $this->categoriesdisplayoptions)) { 2315 return $this->categoriesdisplayoptions[$optionname]; 2316 } else { 2317 return $defaultvalue; 2318 } 2319 } 2320 2321 /** 2322 * Returns all options to display list of subcategories 2323 * 2324 * This array is usually passed to {@link coursecat::get_children()} 2325 * 2326 * @return array 2327 */ 2328 public function get_categories_display_options() { 2329 return $this->categoriesdisplayoptions; 2330 } 2331 2332 /** 2333 * Sets additional general options to pass between renderer functions, usually HTML attributes 2334 * 2335 * @param array $attributes 2336 * @return coursecat_helper 2337 */ 2338 public function set_attributes($attributes) { 2339 $this->attributes = $attributes; 2340 return $this; 2341 } 2342 2343 /** 2344 * Return all attributes and erases them so they are not applied again 2345 * 2346 * @param string $classname adds additional class name to the beginning of $attributes['class'] 2347 * @return array 2348 */ 2349 public function get_and_erase_attributes($classname) { 2350 $attributes = $this->attributes; 2351 $this->attributes = array(); 2352 if (empty($attributes['class'])) { 2353 $attributes['class'] = ''; 2354 } 2355 $attributes['class'] = $classname . ' '. $attributes['class']; 2356 return $attributes; 2357 } 2358 2359 /** 2360 * Sets the search criteria if the course is a search result 2361 * 2362 * Search string will be used to highlight terms in course name and description 2363 * 2364 * @param array $searchcriteria 2365 * @return coursecat_helper 2366 */ 2367 public function set_search_criteria($searchcriteria) { 2368 $this->searchcriteria = $searchcriteria; 2369 return $this; 2370 } 2371 2372 /** 2373 * Returns formatted and filtered description of the given category 2374 * 2375 * @param coursecat $coursecat category 2376 * @param stdClass|array $options format options, by default [noclean,overflowdiv], 2377 * if context is not specified it will be added automatically 2378 * @return string|null 2379 */ 2380 public function get_category_formatted_description($coursecat, $options = null) { 2381 if ($coursecat->id && !empty($coursecat->description)) { 2382 if (!isset($coursecat->descriptionformat)) { 2383 $descriptionformat = FORMAT_MOODLE; 2384 } else { 2385 $descriptionformat = $coursecat->descriptionformat; 2386 } 2387 if ($options === null) { 2388 $options = array('noclean' => true, 'overflowdiv' => true); 2389 } else { 2390 $options = (array)$options; 2391 } 2392 $context = context_coursecat::instance($coursecat->id); 2393 if (!isset($options['context'])) { 2394 $options['context'] = $context; 2395 } 2396 $text = file_rewrite_pluginfile_urls($coursecat->description, 2397 'pluginfile.php', $context->id, 'coursecat', 'description', null); 2398 return format_text($text, $descriptionformat, $options); 2399 } 2400 return null; 2401 } 2402 2403 /** 2404 * Returns given course's summary with proper embedded files urls and formatted 2405 * 2406 * @param course_in_list $course 2407 * @param array|stdClass $options additional formatting options 2408 * @return string 2409 */ 2410 public function get_course_formatted_summary($course, $options = array()) { 2411 global $CFG; 2412 require_once($CFG->libdir. '/filelib.php'); 2413 if (!$course->has_summary()) { 2414 return ''; 2415 } 2416 $options = (array)$options; 2417 $context = context_course::instance($course->id); 2418 if (!isset($options['context'])) { 2419 // TODO see MDL-38521 2420 // option 1 (current), page context - no code required 2421 // option 2, system context 2422 // $options['context'] = context_system::instance(); 2423 // option 3, course context: 2424 // $options['context'] = $context; 2425 // option 4, course category context: 2426 // $options['context'] = $context->get_parent_context(); 2427 } 2428 $summary = file_rewrite_pluginfile_urls($course->summary, 'pluginfile.php', $context->id, 'course', 'summary', null); 2429 $summary = format_text($summary, $course->summaryformat, $options, $course->id); 2430 if (!empty($this->searchcriteria['search'])) { 2431 $summary = highlight($this->searchcriteria['search'], $summary); 2432 } 2433 return $summary; 2434 } 2435 2436 /** 2437 * Returns course name as it is configured to appear in courses lists formatted to course context 2438 * 2439 * @param course_in_list $course 2440 * @param array|stdClass $options additional formatting options 2441 * @return string 2442 */ 2443 public function get_course_formatted_name($course, $options = array()) { 2444 $options = (array)$options; 2445 if (!isset($options['context'])) { 2446 $options['context'] = context_course::instance($course->id); 2447 } 2448 $name = format_string(get_course_display_name_for_list($course), true, $options); 2449 if (!empty($this->searchcriteria['search'])) { 2450 $name = highlight($this->searchcriteria['search'], $name); 2451 } 2452 return $name; 2453 } 2454 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body
Generated: Fri Nov 28 20:29:05 2014 | Cross-referenced by PHPXref 0.7.1 |