Commit | Line | Data |
---|---|---|
24e27ac0 SH |
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 { | |
43e389ea MG |
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; | |
24e27ac0 SH |
42 | |
43 | /** | |
44 | * A cache of strings | |
45 | * @var stdClass | |
46 | */ | |
47 | protected $strings; | |
48 | ||
49 | /** | |
50 | * Override the constructor so that we can initialise the string cache | |
51 | * | |
52 | * @param moodle_page $page | |
53 | * @param string $target | |
54 | */ | |
55 | public function __construct(moodle_page $page, $target) { | |
56 | $this->strings = new stdClass; | |
57 | parent::__construct($page, $target); | |
a03dfb7d MG |
58 | $this->add_modchoosertoggle(); |
59 | } | |
60 | ||
61 | /** | |
62 | * Adds the item in course settings navigation to toggle modchooser | |
63 | * | |
64 | * Theme can overwrite as an empty function to exclude it (for example if theme does not | |
65 | * use modchooser at all) | |
66 | */ | |
67 | protected function add_modchoosertoggle() { | |
68 | global $CFG; | |
69 | static $modchoosertoggleadded = false; | |
70 | // Add the module chooser toggle to the course page | |
71 | if ($modchoosertoggleadded || $this->page->state > moodle_page::STATE_PRINTING_HEADER || | |
72 | $this->page->course->id == SITEID || | |
aa2b293e MG |
73 | !$this->page->user_is_editing() || |
74 | !($context = context_course::instance($this->page->course->id)) || | |
75 | !has_capability('moodle/course:update', $context) || | |
76 | !course_ajax_enabled($this->page->course) || | |
77 | !($coursenode = $this->page->settingsnav->find('courseadmin', navigation_node::TYPE_COURSE)) || | |
78 | !$coursenode->get('editsettings')) { | |
a03dfb7d | 79 | // too late or we are on site page or we could not find the course settings node |
aa2b293e | 80 | // or we are not allowed to edit |
a03dfb7d MG |
81 | return; |
82 | } | |
83 | $modchoosertoggleadded = true; | |
84 | if ($this->page->url->compare(new moodle_url('/course/view.php'), URL_MATCH_BASE)) { | |
85 | // We are on the course page, retain the current page params e.g. section. | |
86 | $modchoosertoggleurl = clone($this->page->url); | |
87 | } else { | |
88 | // Edit on the main course page. | |
89 | $modchoosertoggleurl = new moodle_url('/course/view.php', array('id' => $this->page->course->id, | |
90 | 'return' => $this->page->url->out_as_local_url(false))); | |
91 | } | |
92 | $modchoosertoggleurl->param('sesskey', sesskey()); | |
93 | if ($usemodchooser = get_user_preferences('usemodchooser', $CFG->modchooserdefault)) { | |
94 | $modchoosertogglestring = get_string('modchooserdisable', 'moodle'); | |
95 | $modchoosertoggleurl->param('modchooser', 'off'); | |
96 | } else { | |
97 | $modchoosertogglestring = get_string('modchooserenable', 'moodle'); | |
98 | $modchoosertoggleurl->param('modchooser', 'on'); | |
99 | } | |
100 | $modchoosertoggle = navigation_node::create($modchoosertogglestring, $modchoosertoggleurl, navigation_node::TYPE_SETTING); | |
101 | $coursenode->add_node($modchoosertoggle, 'editsettings'); | |
102 | $modchoosertoggle->add_class('modchoosertoggle'); | |
103 | $modchoosertoggle->add_class('visibleifjs'); | |
104 | user_preference_allow_ajax_update('usemodchooser', PARAM_BOOL); | |
24e27ac0 SH |
105 | } |
106 | ||
cb76fec0 PS |
107 | /** |
108 | * Renders course info box. | |
109 | * | |
e2d70cca | 110 | * @param stdClass|course_in_list $course |
cb76fec0 PS |
111 | * @return string |
112 | */ | |
113 | public function course_info_box(stdClass $course) { | |
cb76fec0 PS |
114 | $content = ''; |
115 | $content .= $this->output->box_start('generalbox info'); | |
e2d70cca MG |
116 | $chelper = new coursecat_helper(); |
117 | $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED); | |
118 | $content .= $this->coursecat_coursebox($chelper, $course); | |
cb76fec0 | 119 | $content .= $this->output->box_end(); |
cb76fec0 PS |
120 | return $content; |
121 | } | |
122 | ||
24e27ac0 SH |
123 | /** |
124 | * Renderers a structured array of courses and categories into a nice | |
125 | * XHTML tree structure. | |
126 | * | |
127 | * This method was designed initially to display the front page course/category | |
128 | * combo view. The structure can be retrieved by get_course_category_tree() | |
129 | * | |
130 | * @param array $structure | |
131 | * @return string | |
132 | */ | |
133 | public function course_category_tree(array $structure) { | |
24e27ac0 SH |
134 | $this->strings->summary = get_string('summary'); |
135 | ||
136 | // Generate an id and the required JS call to make this a nice widget | |
137 | $id = html_writer::random_id('course_category_tree'); | |
c8ffba95 | 138 | $this->page->requires->js_init_call('M.util.init_toggle_class_on_click', array($id, '.category.with_children .category_label', 'collapsed', '.category.with_children')); |
24e27ac0 SH |
139 | |
140 | // Start content generation | |
141 | $content = html_writer::start_tag('div', array('class'=>'course_category_tree', 'id'=>$id)); | |
142 | foreach ($structure as $category) { | |
143 | $content .= $this->course_category_tree_category($category); | |
144 | } | |
145 | $content .= html_writer::start_tag('div', array('class'=>'controls')); | |
146 | $content .= html_writer::tag('div', get_string('collapseall'), array('class'=>'addtoall expandall')); | |
147 | $content .= html_writer::tag('div', get_string('expandall'), array('class'=>'removefromall collapseall')); | |
148 | $content .= html_writer::end_tag('div'); | |
149 | $content .= html_writer::end_tag('div'); | |
df997f84 | 150 | |
24e27ac0 SH |
151 | // Return the course category tree HTML |
152 | return $content; | |
153 | } | |
154 | ||
155 | /** | |
156 | * Renderers a category for use with course_category_tree | |
157 | * | |
158 | * @param array $category | |
159 | * @param int $depth | |
160 | * @return string | |
161 | */ | |
162 | protected function course_category_tree_category(stdClass $category, $depth=1) { | |
163 | $content = ''; | |
3754f4f3 ARN |
164 | $hassubcategories = (isset($category->categories) && count($category->categories)>0); |
165 | $hascourses = (isset($category->courses) && count($category->courses)>0); | |
24e27ac0 SH |
166 | $classes = array('category'); |
167 | if ($category->parent != 0) { | |
168 | $classes[] = 'subcategory'; | |
169 | } | |
d703f226 SH |
170 | if (empty($category->visible)) { |
171 | $classes[] = 'dimmed_category'; | |
172 | } | |
24e27ac0 SH |
173 | if ($hassubcategories || $hascourses) { |
174 | $classes[] = 'with_children'; | |
175 | if ($depth > 1) { | |
176 | $classes[] = 'collapsed'; | |
177 | } | |
178 | } | |
9a5e297b | 179 | $categoryname = format_string($category->name, true, array('context' => context_coursecat::instance($category->id))); |
63390481 | 180 | |
24e27ac0 SH |
181 | $content .= html_writer::start_tag('div', array('class'=>join(' ', $classes))); |
182 | $content .= html_writer::start_tag('div', array('class'=>'category_label')); | |
63390481 | 183 | $content .= html_writer::link(new moodle_url('/course/category.php', array('id'=>$category->id)), $categoryname, array('class'=>'category_link')); |
24e27ac0 SH |
184 | $content .= html_writer::end_tag('div'); |
185 | if ($hassubcategories) { | |
186 | $content .= html_writer::start_tag('div', array('class'=>'subcategories')); | |
187 | foreach ($category->categories as $subcategory) { | |
188 | $content .= $this->course_category_tree_category($subcategory, $depth+1); | |
189 | } | |
190 | $content .= html_writer::end_tag('div'); | |
191 | } | |
192 | if ($hascourses) { | |
193 | $content .= html_writer::start_tag('div', array('class'=>'courses')); | |
194 | $coursecount = 0; | |
6a1273cb | 195 | $strinfo = new lang_string('info'); |
24e27ac0 SH |
196 | foreach ($category->courses as $course) { |
197 | $classes = array('course'); | |
d2fd38be PS |
198 | $linkclass = 'course_link'; |
199 | if (!$course->visible) { | |
200 | $linkclass .= ' dimmed'; | |
201 | } | |
24e27ac0 SH |
202 | $coursecount ++; |
203 | $classes[] = ($coursecount%2)?'odd':'even'; | |
204 | $content .= html_writer::start_tag('div', array('class'=>join(' ', $classes))); | |
f4c23f03 | 205 | $content .= html_writer::link(new moodle_url('/course/view.php', array('id'=>$course->id)), format_string($course->fullname), array('class'=>$linkclass)); |
24e27ac0 SH |
206 | $content .= html_writer::start_tag('div', array('class'=>'course_info clearfix')); |
207 | ||
bf423bb1 PS |
208 | // print enrol info |
209 | if ($icons = enrol_get_course_info_icons($course)) { | |
210 | foreach ($icons as $pix_icon) { | |
211 | $content .= $this->render($pix_icon); | |
212 | } | |
213 | } | |
214 | ||
24e27ac0 | 215 | if ($course->summary) { |
6a1273cb | 216 | $url = new moodle_url('/course/info.php', array('id' => $course->id)); |
24e27ac0 | 217 | $image = html_writer::empty_tag('img', array('src'=>$this->output->pix_url('i/info'), 'alt'=>$this->strings->summary)); |
6a1273cb | 218 | $content .= $this->action_link($url, $image, new popup_action('click', $url, 'courseinfo'), array('title' => $this->strings->summary)); |
24e27ac0 SH |
219 | } |
220 | $content .= html_writer::end_tag('div'); | |
221 | $content .= html_writer::end_tag('div'); | |
222 | } | |
223 | $content .= html_writer::end_tag('div'); | |
224 | } | |
225 | $content .= html_writer::end_tag('div'); | |
226 | return $content; | |
227 | } | |
01e0e704 ARN |
228 | |
229 | /** | |
230 | * Build the HTML for the module chooser javascript popup | |
231 | * | |
232 | * @param array $modules A set of modules as returned form @see | |
233 | * get_module_metadata | |
234 | * @param object $course The course that will be displayed | |
235 | * @return string The composed HTML for the module | |
236 | */ | |
237 | public function course_modchooser($modules, $course) { | |
697ff999 MG |
238 | static $isdisplayed = false; |
239 | if ($isdisplayed) { | |
240 | return ''; | |
241 | } | |
242 | $isdisplayed = true; | |
243 | ||
244 | // Add the module chooser | |
245 | $this->page->requires->yui_module('moodle-course-modchooser', | |
246 | 'M.course.init_chooser', | |
247 | array(array('courseid' => $course->id, 'closeButtonTitle' => get_string('close', 'editor'))) | |
248 | ); | |
249 | $this->page->requires->strings_for_js(array( | |
250 | 'addresourceoractivity', | |
251 | 'modchooserenable', | |
252 | 'modchooserdisable', | |
253 | ), 'moodle'); | |
01e0e704 ARN |
254 | |
255 | // Add the header | |
1edff8c7 | 256 | $header = html_writer::tag('div', get_string('addresourceoractivity', 'moodle'), |
255dd8d1 | 257 | array('class' => 'hd choosertitle')); |
01e0e704 ARN |
258 | |
259 | $formcontent = html_writer::start_tag('form', array('action' => new moodle_url('/course/jumpto.php'), | |
260 | 'id' => 'chooserform', 'method' => 'post')); | |
261 | $formcontent .= html_writer::start_tag('div', array('id' => 'typeformdiv')); | |
262 | $formcontent .= html_writer::tag('input', '', array('type' => 'hidden', 'id' => 'course', | |
263 | 'name' => 'course', 'value' => $course->id)); | |
264 | $formcontent .= html_writer::tag('input', '', | |
0a2fb910 | 265 | array('type' => 'hidden', 'class' => 'jump', 'name' => 'jump', 'value' => '')); |
01e0e704 ARN |
266 | $formcontent .= html_writer::tag('input', '', array('type' => 'hidden', 'name' => 'sesskey', |
267 | 'value' => sesskey())); | |
268 | $formcontent .= html_writer::end_tag('div'); | |
269 | ||
270 | // Put everything into one tag 'options' | |
271 | $formcontent .= html_writer::start_tag('div', array('class' => 'options')); | |
272 | $formcontent .= html_writer::tag('div', get_string('selectmoduletoviewhelp', 'moodle'), | |
273 | array('class' => 'instruction')); | |
274 | // Put all options into one tag 'alloptions' to allow us to handle scrolling | |
275 | $formcontent .= html_writer::start_tag('div', array('class' => 'alloptions')); | |
276 | ||
5035ed63 MA |
277 | // Activities |
278 | $activities = array_filter($modules, function($mod) { | |
279 | return ($mod->archetype !== MOD_ARCHETYPE_RESOURCE && $mod->archetype !== MOD_ARCHETYPE_SYSTEM); | |
280 | }); | |
01e0e704 ARN |
281 | if (count($activities)) { |
282 | $formcontent .= $this->course_modchooser_title('activities'); | |
283 | $formcontent .= $this->course_modchooser_module_types($activities); | |
284 | } | |
285 | ||
463ccee1 | 286 | // Resources |
5035ed63 MA |
287 | $resources = array_filter($modules, function($mod) { |
288 | return ($mod->archetype === MOD_ARCHETYPE_RESOURCE); | |
289 | }); | |
48a5e55e ARN |
290 | if (count($resources)) { |
291 | $formcontent .= $this->course_modchooser_title('resources'); | |
292 | $formcontent .= $this->course_modchooser_module_types($resources); | |
293 | } | |
294 | ||
01e0e704 ARN |
295 | $formcontent .= html_writer::end_tag('div'); // modoptions |
296 | $formcontent .= html_writer::end_tag('div'); // types | |
297 | ||
298 | $formcontent .= html_writer::start_tag('div', array('class' => 'submitbuttons')); | |
af75421c | 299 | $formcontent .= html_writer::tag('input', '', |
0a2fb910 | 300 | array('type' => 'submit', 'name' => 'submitbutton', 'class' => 'submitbutton', 'value' => get_string('add'))); |
8ff6c5ee | 301 | $formcontent .= html_writer::tag('input', '', |
0a2fb910 | 302 | array('type' => 'submit', 'name' => 'addcancel', 'class' => 'addcancel', 'value' => get_string('cancel'))); |
01e0e704 ARN |
303 | $formcontent .= html_writer::end_tag('div'); |
304 | $formcontent .= html_writer::end_tag('form'); | |
305 | ||
306 | // Wrap the whole form in a div | |
307 | $formcontent = html_writer::tag('div', $formcontent, array('id' => 'chooseform')); | |
308 | ||
309 | // Put all of the content together | |
310 | $content = $formcontent; | |
311 | ||
255dd8d1 ARN |
312 | $content = html_writer::tag('div', $content, array('class' => 'choosercontainer')); |
313 | return $header . html_writer::tag('div', $content, array('class' => 'chooserdialoguebody')); | |
01e0e704 ARN |
314 | } |
315 | ||
316 | /** | |
317 | * Build the HTML for a specified set of modules | |
318 | * | |
319 | * @param array $modules A set of modules as used by the | |
320 | * course_modchooser_module function | |
321 | * @return string The composed HTML for the module | |
322 | */ | |
323 | protected function course_modchooser_module_types($modules) { | |
324 | $return = ''; | |
325 | foreach ($modules as $module) { | |
326 | if (!isset($module->types)) { | |
327 | $return .= $this->course_modchooser_module($module); | |
328 | } else { | |
329 | $return .= $this->course_modchooser_module($module, array('nonoption')); | |
330 | foreach ($module->types as $type) { | |
331 | $return .= $this->course_modchooser_module($type, array('option', 'subtype')); | |
332 | } | |
333 | } | |
334 | } | |
335 | return $return; | |
336 | } | |
337 | ||
338 | /** | |
339 | * Return the HTML for the specified module adding any required classes | |
340 | * | |
341 | * @param object $module An object containing the title, and link. An | |
342 | * icon, and help text may optionally be specified. If the module | |
343 | * contains subtypes in the types option, then these will also be | |
344 | * displayed. | |
345 | * @param array $classes Additional classes to add to the encompassing | |
346 | * div element | |
347 | * @return string The composed HTML for the module | |
348 | */ | |
349 | protected function course_modchooser_module($module, $classes = array('option')) { | |
350 | $output = ''; | |
351 | $output .= html_writer::start_tag('div', array('class' => implode(' ', $classes))); | |
352 | $output .= html_writer::start_tag('label', array('for' => 'module_' . $module->name)); | |
353 | if (!isset($module->types)) { | |
354 | $output .= html_writer::tag('input', '', array('type' => 'radio', | |
355 | 'name' => 'jumplink', 'id' => 'module_' . $module->name, 'value' => $module->link)); | |
356 | } | |
357 | ||
358 | $output .= html_writer::start_tag('span', array('class' => 'modicon')); | |
359 | if (isset($module->icon)) { | |
360 | // Add an icon if we have one | |
361 | $output .= $module->icon; | |
362 | } | |
363 | $output .= html_writer::end_tag('span'); | |
364 | ||
365 | $output .= html_writer::tag('span', $module->title, array('class' => 'typename')); | |
366 | if (!isset($module->help)) { | |
367 | // Add help if found | |
368 | $module->help = get_string('nohelpforactivityorresource', 'moodle'); | |
369 | } | |
370 | ||
371 | // Format the help text using markdown with the following options | |
372 | $options = new stdClass(); | |
373 | $options->trusted = false; | |
374 | $options->noclean = false; | |
375 | $options->smiley = false; | |
376 | $options->filter = false; | |
377 | $options->para = true; | |
378 | $options->newlines = false; | |
379 | $options->overflowdiv = false; | |
380 | $module->help = format_text($module->help, FORMAT_MARKDOWN, $options); | |
381 | $output .= html_writer::tag('span', $module->help, array('class' => 'typesummary')); | |
382 | $output .= html_writer::end_tag('label'); | |
383 | $output .= html_writer::end_tag('div'); | |
384 | ||
385 | return $output; | |
386 | } | |
387 | ||
388 | protected function course_modchooser_title($title, $identifier = null) { | |
389 | $module = new stdClass(); | |
390 | $module->name = $title; | |
391 | $module->types = array(); | |
392 | $module->title = get_string($title, $identifier); | |
393 | $module->help = ''; | |
394 | return $this->course_modchooser_module($module, array('moduletypetitle')); | |
395 | } | |
f558b291 MG |
396 | |
397 | /** | |
398 | * Renders HTML for displaying the sequence of course module editing buttons | |
399 | * | |
400 | * @see course_get_cm_edit_actions() | |
401 | * | |
402 | * @param array $actions array of action_link or pix_icon objects | |
403 | * @return string | |
404 | */ | |
405 | public function course_section_cm_edit_actions($actions) { | |
406 | $output = html_writer::start_tag('span', array('class' => 'commands')); | |
407 | foreach ($actions as $action) { | |
408 | if ($action instanceof renderable) { | |
409 | $output .= $this->output->render($action); | |
410 | } else { | |
411 | $output .= $action; | |
412 | } | |
413 | } | |
414 | $output .= html_writer::end_tag('span'); | |
415 | return $output; | |
416 | } | |
9a6aa5c1 MG |
417 | |
418 | /** | |
419 | * Renders HTML for the menus to add activities and resources to the current course | |
420 | * | |
a03dfb7d MG |
421 | * Note, if theme overwrites this function and it does not use modchooser, |
422 | * see also {@link core_course_renderer::add_modchoosertoggle()} | |
423 | * | |
9a6aa5c1 MG |
424 | * @param stdClass $course |
425 | * @param int $section relative section number (field course_sections.section) | |
426 | * @param int $sectionreturn The section to link back to | |
427 | * @param array $displayoptions additional display options, for example blocks add | |
428 | * option 'inblock' => true, suggesting to display controls vertically | |
429 | * @return string | |
430 | */ | |
431 | function course_section_add_cm_control($course, $section, $sectionreturn = null, $displayoptions = array()) { | |
432 | global $CFG; | |
433 | ||
434 | $vertical = !empty($displayoptions['inblock']); | |
435 | ||
436 | // check to see if user can add menus and there are modules to add | |
437 | if (!has_capability('moodle/course:manageactivities', context_course::instance($course->id)) | |
438 | || !$this->page->user_is_editing() | |
439 | || !($modnames = get_module_types_names()) || empty($modnames)) { | |
440 | return ''; | |
441 | } | |
442 | ||
443 | // Retrieve all modules with associated metadata | |
444 | $modules = get_module_metadata($course, $modnames, $sectionreturn); | |
445 | $urlparams = array('section' => $section); | |
446 | ||
447 | // We'll sort resources and activities into two lists | |
448 | $activities = array(MOD_CLASS_ACTIVITY => array(), MOD_CLASS_RESOURCE => array()); | |
449 | ||
450 | foreach ($modules as $module) { | |
451 | if (!array_key_exists($module->archetype, $activities)) { | |
452 | // System modules cannot be added by user, do not add to dropdown | |
453 | } else if (isset($module->types)) { | |
454 | // This module has a subtype | |
455 | // NOTE: this is legacy stuff, module subtypes are very strongly discouraged!! | |
456 | $subtypes = array(); | |
457 | foreach ($module->types as $subtype) { | |
458 | $link = $subtype->link->out(true, $urlparams); | |
459 | $subtypes[$link] = $subtype->title; | |
460 | } | |
461 | ||
462 | // Sort module subtypes into the list | |
463 | if (!empty($module->title)) { | |
464 | // This grouping has a name | |
465 | $activities[$module->archetype][] = array($module->title => $subtypes); | |
466 | } else { | |
467 | // This grouping does not have a name | |
468 | $activities[$module->archetype] = array_merge($activities[$module->archetype], $subtypes); | |
469 | } | |
470 | } else { | |
471 | // This module has no subtypes | |
472 | $link = $module->link->out(true, $urlparams); | |
473 | $activities[$module->archetype][$link] = $module->title; | |
474 | } | |
475 | } | |
476 | ||
477 | $straddactivity = get_string('addactivity'); | |
478 | $straddresource = get_string('addresource'); | |
479 | $sectionname = get_section_name($course, $section); | |
480 | $strresourcelabel = get_string('addresourcetosection', null, $sectionname); | |
481 | $stractivitylabel = get_string('addactivitytosection', null, $sectionname); | |
482 | ||
483 | $output = html_writer::start_tag('div', array('class' => 'section_add_menus', 'id' => 'add_menus-section-' . $section)); | |
484 | ||
485 | if (!$vertical) { | |
486 | $output .= html_writer::start_tag('div', array('class' => 'horizontal')); | |
487 | } | |
488 | ||
489 | if (!empty($activities[MOD_CLASS_RESOURCE])) { | |
490 | $select = new url_select($activities[MOD_CLASS_RESOURCE], '', array(''=>$straddresource), "ressection$section"); | |
491 | $select->set_help_icon('resources'); | |
492 | $select->set_label($strresourcelabel, array('class' => 'accesshide')); | |
493 | $output .= $this->output->render($select); | |
494 | } | |
495 | ||
496 | if (!empty($activities[MOD_CLASS_ACTIVITY])) { | |
497 | $select = new url_select($activities[MOD_CLASS_ACTIVITY], '', array(''=>$straddactivity), "section$section"); | |
498 | $select->set_help_icon('activities'); | |
499 | $select->set_label($stractivitylabel, array('class' => 'accesshide')); | |
500 | $output .= $this->output->render($select); | |
501 | } | |
502 | ||
503 | if (!$vertical) { | |
504 | $output .= html_writer::end_tag('div'); | |
505 | } | |
506 | ||
507 | $output .= html_writer::end_tag('div'); | |
508 | ||
509 | if (course_ajax_enabled($course) && $course->id == $this->page->course->id) { | |
510 | // modchooser can be added only for the current course set on the page! | |
511 | $straddeither = get_string('addresourceoractivity'); | |
512 | // The module chooser link | |
513 | $modchooser = html_writer::start_tag('div', array('class' => 'mdl-right')); | |
514 | $modchooser.= html_writer::start_tag('div', array('class' => 'section-modchooser')); | |
515 | $icon = $this->output->pix_icon('t/add', ''); | |
516 | $span = html_writer::tag('span', $straddeither, array('class' => 'section-modchooser-text')); | |
517 | $modchooser .= html_writer::tag('span', $icon . $span, array('class' => 'section-modchooser-link')); | |
518 | $modchooser.= html_writer::end_tag('div'); | |
519 | $modchooser.= html_writer::end_tag('div'); | |
520 | ||
521 | // Wrap the normal output in a noscript div | |
522 | $usemodchooser = get_user_preferences('usemodchooser', $CFG->modchooserdefault); | |
523 | if ($usemodchooser) { | |
524 | $output = html_writer::tag('div', $output, array('class' => 'hiddenifjs addresourcedropdown')); | |
525 | $modchooser = html_writer::tag('div', $modchooser, array('class' => 'visibleifjs addresourcemodchooser')); | |
526 | } else { | |
527 | // If the module chooser is disabled, we need to ensure that the dropdowns are shown even if javascript is disabled | |
528 | $output = html_writer::tag('div', $output, array('class' => 'show addresourcedropdown')); | |
529 | $modchooser = html_writer::tag('div', $modchooser, array('class' => 'hide addresourcemodchooser')); | |
530 | } | |
531 | $output = $this->course_modchooser($modules, $course) . $modchooser . $output; | |
532 | } | |
533 | ||
534 | return $output; | |
535 | } | |
7e29340f | 536 | |
f4b571ab MG |
537 | /** |
538 | * Renders html to display a course search form | |
539 | * | |
540 | * @param string $value default value to populate the search field | |
541 | * @param string $format display format - 'plain' (default), 'short' or 'navbar' | |
542 | * @return string | |
543 | */ | |
544 | function course_search_form($value = '', $format = 'plain') { | |
545 | static $count = 0; | |
546 | $formid = 'coursesearch'; | |
547 | if ((++$count) > 1) { | |
548 | $formid .= $count; | |
549 | } | |
550 | ||
551 | switch ($format) { | |
552 | case 'navbar' : | |
553 | $formid = 'coursesearchnavbar'; | |
554 | $inputid = 'navsearchbox'; | |
555 | $inputsize = 20; | |
556 | break; | |
557 | case 'short' : | |
558 | $inputid = 'shortsearchbox'; | |
559 | $inputsize = 12; | |
560 | break; | |
561 | default : | |
562 | $inputid = 'coursesearchbox'; | |
563 | $inputsize = 30; | |
564 | } | |
565 | ||
566 | $strsearchcourses= get_string("searchcourses"); | |
567 | $searchurl = new moodle_url('/course/search.php'); | |
568 | ||
569 | $output = html_writer::start_tag('form', array('id' => $formid, 'action' => $searchurl, 'method' => 'get')); | |
570 | $output .= html_writer::start_tag('fieldset', array('class' => 'coursesearchbox invisiblefieldset')); | |
571 | $output .= html_writer::tag('lavel', $strsearchcourses.': ', array('for' => $inputid)); | |
572 | $output .= html_writer::empty_tag('input', array('type' => 'text', 'id' => $inputid, | |
573 | 'size' => $inputsize, 'name' => 'search', 'value' => s($value))); | |
574 | $output .= html_writer::empty_tag('input', array('type' => 'submit', | |
575 | 'value' => get_string('go'))); | |
576 | $output .= html_writer::end_tag('fieldset'); | |
577 | $output .= html_writer::end_tag('form'); | |
578 | ||
579 | return $output; | |
580 | } | |
581 | ||
7e29340f MG |
582 | /** |
583 | * Renders html for completion box on course page | |
584 | * | |
585 | * If completion is disabled, returns empty string | |
586 | * If completion is automatic, returns an icon of the current completion state | |
587 | * If completion is manual, returns a form (with an icon inside) that allows user to | |
588 | * toggle completion | |
589 | * | |
590 | * @param stdClass $course course object | |
591 | * @param completion_info $completioninfo completion info for the course, it is recommended | |
592 | * to fetch once for all modules in course/section for performance | |
593 | * @param cm_info $mod module to show completion for | |
594 | * @param array $displayoptions display options, not used in core | |
595 | * @return string | |
596 | */ | |
597 | public function course_section_cm_completion($course, &$completioninfo, cm_info $mod, $displayoptions = array()) { | |
598 | global $CFG; | |
599 | $output = ''; | |
600 | if (!empty($displayoptions['hidecompletion']) || !isloggedin() || isguestuser() || !$mod->uservisible) { | |
601 | return $output; | |
602 | } | |
603 | if ($completioninfo === null) { | |
604 | $completioninfo = new completion_info($course); | |
605 | } | |
606 | $completion = $completioninfo->is_enabled($mod); | |
607 | if ($completion == COMPLETION_TRACKING_NONE) { | |
608 | return $output; | |
609 | } | |
610 | ||
611 | $completiondata = $completioninfo->get_data($mod, true); | |
612 | $completionicon = ''; | |
613 | ||
614 | if ($this->page->user_is_editing()) { | |
615 | switch ($completion) { | |
616 | case COMPLETION_TRACKING_MANUAL : | |
617 | $completionicon = 'manual-enabled'; break; | |
618 | case COMPLETION_TRACKING_AUTOMATIC : | |
619 | $completionicon = 'auto-enabled'; break; | |
620 | } | |
621 | } else if ($completion == COMPLETION_TRACKING_MANUAL) { | |
622 | switch($completiondata->completionstate) { | |
623 | case COMPLETION_INCOMPLETE: | |
624 | $completionicon = 'manual-n'; break; | |
625 | case COMPLETION_COMPLETE: | |
626 | $completionicon = 'manual-y'; break; | |
627 | } | |
628 | } else { // Automatic | |
629 | switch($completiondata->completionstate) { | |
630 | case COMPLETION_INCOMPLETE: | |
631 | $completionicon = 'auto-n'; break; | |
632 | case COMPLETION_COMPLETE: | |
633 | $completionicon = 'auto-y'; break; | |
634 | case COMPLETION_COMPLETE_PASS: | |
635 | $completionicon = 'auto-pass'; break; | |
636 | case COMPLETION_COMPLETE_FAIL: | |
637 | $completionicon = 'auto-fail'; break; | |
638 | } | |
639 | } | |
640 | if ($completionicon) { | |
641 | $formattedname = $mod->get_formatted_name(); | |
642 | $imgalt = get_string('completion-alt-' . $completionicon, 'completion', $formattedname); | |
643 | if ($completion == COMPLETION_TRACKING_MANUAL && !$this->page->user_is_editing()) { | |
644 | $imgtitle = get_string('completion-title-' . $completionicon, 'completion', $formattedname); | |
645 | $newstate = | |
646 | $completiondata->completionstate == COMPLETION_COMPLETE | |
647 | ? COMPLETION_INCOMPLETE | |
648 | : COMPLETION_COMPLETE; | |
649 | // In manual mode the icon is a toggle form... | |
650 | ||
651 | // If this completion state is used by the | |
652 | // conditional activities system, we need to turn | |
653 | // off the JS. | |
654 | $extraclass = ''; | |
655 | if (!empty($CFG->enableavailability) && | |
656 | condition_info::completion_value_used_as_condition($course, $mod)) { | |
657 | $extraclass = ' preventjs'; | |
658 | } | |
659 | $output .= html_writer::start_tag('form', array('method' => 'post', | |
660 | 'action' => new moodle_url('/course/togglecompletion.php'), | |
661 | 'class' => 'togglecompletion'. $extraclass)); | |
662 | $output .= html_writer::start_tag('div'); | |
663 | $output .= html_writer::empty_tag('input', array( | |
664 | 'type' => 'hidden', 'name' => 'id', 'value' => $mod->id)); | |
665 | $output .= html_writer::empty_tag('input', array( | |
666 | 'type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())); | |
667 | $output .= html_writer::empty_tag('input', array( | |
668 | 'type' => 'hidden', 'name' => 'modulename', 'value' => $mod->name)); | |
669 | $output .= html_writer::empty_tag('input', array( | |
670 | 'type' => 'hidden', 'name' => 'completionstate', 'value' => $newstate)); | |
671 | $output .= html_writer::empty_tag('input', array( | |
672 | 'type' => 'image', | |
673 | 'src' => $this->output->pix_url('i/completion-'.$completionicon), | |
f0989c3b RT |
674 | 'alt' => $imgalt, 'title' => $imgtitle, |
675 | 'aria-live' => 'polite')); | |
7e29340f MG |
676 | $output .= html_writer::end_tag('div'); |
677 | $output .= html_writer::end_tag('form'); | |
678 | } else { | |
679 | // In auto mode, or when editing, the icon is just an image | |
680 | $completionpixicon = new pix_icon('i/completion-'.$completionicon, $imgalt, '', | |
681 | array('title' => $imgalt)); | |
682 | $output .= html_writer::tag('span', $this->output->render($completionpixicon), | |
683 | array('class' => 'autocompletion')); | |
684 | } | |
685 | } | |
686 | return $output; | |
687 | } | |
ed513fad MG |
688 | |
689 | /** | |
690 | * Checks if course module has any conditions that may make it unavailable for | |
691 | * all or some of the students | |
692 | * | |
693 | * This function is internal and is only used to create CSS classes for the module name/text | |
694 | * | |
695 | * @param cm_info $mod | |
696 | * @return bool | |
697 | */ | |
698 | protected function is_cm_conditionally_hidden(cm_info $mod) { | |
699 | global $CFG; | |
700 | $conditionalhidden = false; | |
701 | if (!empty($CFG->enableavailability)) { | |
702 | $conditionalhidden = $mod->availablefrom > time() || | |
703 | ($mod->availableuntil && $mod->availableuntil < time()) || | |
704 | count($mod->conditionsgrade) > 0 || | |
705 | count($mod->conditionscompletion) > 0; | |
706 | } | |
707 | return $conditionalhidden; | |
708 | } | |
709 | ||
710 | /** | |
711 | * Renders html to display a name with the link to the course module on a course page | |
712 | * | |
713 | * If module is unavailable for user but still needs to be displayed | |
714 | * in the list, just the name is returned without a link | |
715 | * | |
716 | * Note, that for course modules that never have separate pages (i.e. labels) | |
717 | * this function return an empty string | |
718 | * | |
719 | * @param cm_info $mod | |
720 | * @param array $displayoptions | |
721 | * @return string | |
722 | */ | |
723 | public function course_section_cm_name(cm_info $mod, $displayoptions = array()) { | |
724 | global $CFG; | |
725 | $output = ''; | |
726 | if (!$mod->uservisible && | |
727 | (empty($mod->showavailability) || empty($mod->availableinfo))) { | |
728 | // nothing to be displayed to the user | |
729 | return $output; | |
730 | } | |
731 | $url = $mod->get_url(); | |
732 | if (!$url) { | |
733 | return $output; | |
734 | } | |
735 | ||
736 | //Accessibility: for files get description via icon, this is very ugly hack! | |
737 | $instancename = $mod->get_formatted_name(); | |
738 | $altname = ''; | |
739 | $altname = $mod->modfullname; | |
740 | // Avoid unnecessary duplication: if e.g. a forum name already | |
741 | // includes the word forum (or Forum, etc) then it is unhelpful | |
742 | // to include that in the accessible description that is added. | |
743 | if (false !== strpos(textlib::strtolower($instancename), | |
744 | textlib::strtolower($altname))) { | |
745 | $altname = ''; | |
746 | } | |
747 | // File type after name, for alphabetic lists (screen reader). | |
748 | if ($altname) { | |
749 | $altname = get_accesshide(' '.$altname); | |
750 | } | |
751 | ||
752 | $conditionalhidden = $this->is_cm_conditionally_hidden($mod); | |
753 | $accessiblebutdim = !$mod->visible || $conditionalhidden; | |
754 | ||
755 | $linkclasses = ''; | |
756 | $accesstext = ''; | |
757 | $textclasses = ''; | |
758 | if ($accessiblebutdim) { | |
759 | $linkclasses .= ' dimmed'; | |
760 | $textclasses .= ' dimmed_text'; | |
761 | if ($conditionalhidden) { | |
762 | $linkclasses .= ' conditionalhidden'; | |
763 | $textclasses .= ' conditionalhidden'; | |
764 | } | |
765 | if ($mod->uservisible) { | |
766 | // show accessibility note only if user can access the module himself | |
767 | $accesstext = get_accesshide(get_string('hiddenfromstudents').': '); | |
768 | } | |
769 | } | |
770 | ||
771 | // Get on-click attribute value if specified and decode the onclick - it | |
772 | // has already been encoded for display (puke). | |
773 | $onclick = htmlspecialchars_decode($mod->get_on_click(), ENT_QUOTES); | |
774 | ||
775 | $groupinglabel = ''; | |
776 | if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', context_course::instance($mod->course))) { | |
777 | $groupings = groups_get_all_groupings($mod->course); | |
778 | $groupinglabel = html_writer::tag('span', '('.format_string($groupings[$mod->groupingid]->name).')', | |
779 | array('class' => 'groupinglabel '.$textclasses)); | |
780 | } | |
781 | ||
782 | // Display link itself. | |
783 | $activitylink = html_writer::empty_tag('img', array('src' => $mod->get_icon_url(), | |
784 | 'class' => 'iconlarge activityicon', 'alt' => $mod->modfullname)) . $accesstext . | |
785 | html_writer::tag('span', $instancename . $altname, array('class' => 'instancename')); | |
786 | if ($mod->uservisible) { | |
787 | $output .= html_writer::link($url, $activitylink, array('class' => $linkclasses, 'onclick' => $onclick)) . | |
788 | $groupinglabel; | |
789 | } else { | |
790 | // We may be displaying this just in order to show information | |
791 | // about visibility, without the actual link ($mod->uservisible) | |
792 | $output .= html_writer::tag('div', $activitylink, array('class' => $textclasses)) . | |
793 | $groupinglabel; | |
794 | } | |
795 | return $output; | |
796 | } | |
797 | ||
798 | /** | |
799 | * Renders html to display the module content on the course page (i.e. text of the labels) | |
800 | * | |
801 | * @param cm_info $mod | |
802 | * @param array $displayoptions | |
803 | * @return string | |
804 | */ | |
805 | public function course_section_cm_text(cm_info $mod, $displayoptions = array()) { | |
806 | $output = ''; | |
807 | if (!$mod->uservisible && | |
808 | (empty($mod->showavailability) || empty($mod->availableinfo))) { | |
809 | // nothing to be displayed to the user | |
810 | return $output; | |
811 | } | |
812 | $content = $mod->get_formatted_content(array('overflowdiv' => true, 'noclean' => true)); | |
813 | $conditionalhidden = $this->is_cm_conditionally_hidden($mod); | |
814 | $accessiblebutdim = !$mod->visible || $conditionalhidden; | |
815 | $textclasses = ''; | |
816 | $accesstext = ''; | |
817 | if ($accessiblebutdim) { | |
818 | $textclasses .= ' dimmed_text'; | |
819 | if ($conditionalhidden) { | |
820 | $textclasses .= ' conditionalhidden'; | |
821 | } | |
822 | if ($mod->uservisible) { | |
823 | // show accessibility note only if user can access the module himself | |
824 | $accesstext = get_accesshide(get_string('hiddenfromstudents').': '); | |
825 | } | |
826 | } | |
827 | if ($mod->get_url()) { | |
828 | if ($content) { | |
829 | // If specified, display extra content after link. | |
830 | $output = html_writer::tag('div', $content, array('class' => | |
831 | trim('contentafterlink ' . $textclasses))); | |
832 | } | |
833 | } else { | |
834 | // No link, so display only content. | |
835 | $output = html_writer::tag('div', $accesstext . $content, array('class' => $textclasses)); | |
836 | } | |
837 | return $output; | |
838 | } | |
839 | ||
840 | /** | |
841 | * Renders HTML to show course module availability information (for someone who isn't allowed | |
842 | * to see the activity itself, or for staff) | |
843 | * | |
844 | * @param cm_info $mod | |
845 | * @param array $displayoptions | |
846 | * @return string | |
847 | */ | |
848 | public function course_section_cm_availability(cm_info $mod, $displayoptions = array()) { | |
849 | global $CFG; | |
850 | if (!$mod->uservisible) { | |
851 | // this is a student who is not allowed to see the module but might be allowed | |
852 | // to see availability info (i.e. "Available from ...") | |
853 | if (!empty($mod->showavailability) && !empty($mod->availableinfo)) { | |
854 | $output = html_writer::tag('div', $mod->availableinfo, array('class' => 'availabilityinfo')); | |
855 | } | |
856 | return $output; | |
857 | } | |
858 | // this is a teacher who is allowed to see module but still should see the | |
859 | // information that module is not available to all/some students | |
860 | $modcontext = context_module::instance($mod->id); | |
861 | $canviewhidden = has_capability('moodle/course:viewhiddenactivities', $modcontext); | |
862 | if ($canviewhidden && !empty($CFG->enableavailability)) { | |
863 | // Don't add availability information if user is not editing and activity is hidden. | |
864 | if ($mod->visible || $this->page->user_is_editing()) { | |
865 | $hidinfoclass = ''; | |
866 | if (!$mod->visible) { | |
867 | $hidinfoclass = 'hide'; | |
868 | } | |
869 | $ci = new condition_info($mod); | |
870 | $fullinfo = $ci->get_full_information(); | |
871 | if($fullinfo) { | |
db82b130 | 872 | return '<div class="availabilityinfo '.$hidinfoclass.'">'.get_string($mod->showavailability |
ed513fad MG |
873 | ? 'userrestriction_visible' |
874 | : 'userrestriction_hidden','condition', | |
875 | $fullinfo).'</div>'; | |
876 | } | |
877 | } | |
878 | } | |
879 | return ''; | |
880 | } | |
c58a25d6 MG |
881 | |
882 | /** | |
883 | * Renders HTML to display one course module in a course section | |
884 | * | |
885 | * This includes link, content, availability, completion info and additional information | |
886 | * that module type wants to display (i.e. number of unread forum posts) | |
887 | * | |
888 | * This function calls: | |
889 | * {@link core_course_renderer::course_section_cm_name()} | |
890 | * {@link cm_info::get_after_link()} | |
891 | * {@link core_course_renderer::course_section_cm_text()} | |
892 | * {@link core_course_renderer::course_section_cm_availability()} | |
893 | * {@link core_course_renderer::course_section_cm_completion()} | |
894 | * {@link course_get_cm_edit_actions()} | |
895 | * {@link core_course_renderer::course_section_cm_edit_actions()} | |
33919cca | 896 | * |
c58a25d6 MG |
897 | * @param stdClass $course |
898 | * @param completion_info $completioninfo | |
899 | * @param cm_info $mod | |
900 | * @param int|null $sectionreturn | |
901 | * @param array $displayoptions | |
902 | * @return string | |
903 | */ | |
904 | public function course_section_cm($course, &$completioninfo, cm_info $mod, $sectionreturn, $displayoptions = array()) { | |
905 | $output = ''; | |
906 | // We return empty string (because course module will not be displayed at all) | |
907 | // if: | |
908 | // 1) The activity is not visible to users | |
909 | // and | |
910 | // 2a) The 'showavailability' option is not set (if that is set, | |
911 | // we need to display the activity so we can show | |
912 | // availability info) | |
913 | // or | |
914 | // 2b) The 'availableinfo' is empty, i.e. the activity was | |
915 | // hidden in a way that leaves no info, such as using the | |
916 | // eye icon. | |
917 | if (!$mod->uservisible && | |
918 | (empty($mod->showavailability) || empty($mod->availableinfo))) { | |
919 | return $output; | |
920 | } | |
921 | ||
922 | $indentclasses = 'mod-indent'; | |
923 | if (!empty($mod->indent)) { | |
924 | $indentclasses .= ' mod-indent-'.$mod->indent; | |
925 | if ($mod->indent > 15) { | |
926 | $indentclasses .= ' mod-indent-huge'; | |
927 | } | |
928 | } | |
929 | $output .= html_writer::start_tag('div', array('class' => $indentclasses)); | |
930 | ||
931 | // Start the div for the activity title, excluding the edit icons. | |
932 | $output .= html_writer::start_tag('div', array('class' => 'activityinstance')); | |
933 | ||
934 | // Display the link to the module (or do nothing if module has no url) | |
935 | $output .= $this->course_section_cm_name($mod, $displayoptions); | |
936 | ||
937 | // Module can put text after the link (e.g. forum unread) | |
938 | $output .= $mod->get_after_link(); | |
939 | ||
940 | // Closing the tag which contains everything but edit icons. Content part of the module should not be part of this. | |
941 | $output .= html_writer::end_tag('div'); // .activityinstance | |
942 | ||
943 | // If there is content but NO link (eg label), then display the | |
944 | // content here (BEFORE any icons). In this case cons must be | |
945 | // displayed after the content so that it makes more sense visually | |
946 | // and for accessibility reasons, e.g. if you have a one-line label | |
947 | // it should work similarly (at least in terms of ordering) to an | |
948 | // activity. | |
949 | $contentpart = $this->course_section_cm_text($mod, $displayoptions); | |
950 | $url = $mod->get_url(); | |
951 | if (empty($url)) { | |
952 | $output .= $contentpart; | |
953 | } | |
954 | ||
955 | if ($this->page->user_is_editing()) { | |
956 | $editactions = course_get_cm_edit_actions($mod, $mod->indent, $sectionreturn); | |
957 | $output .= ' '. $this->course_section_cm_edit_actions($editactions); | |
958 | $output .= $mod->get_after_edit_icons(); | |
959 | } | |
960 | ||
961 | $output .= $this->course_section_cm_completion($course, $completioninfo, $mod, $displayoptions); | |
962 | ||
963 | // If there is content AND a link, then display the content here | |
964 | // (AFTER any icons). Otherwise it was displayed before | |
965 | if (!empty($url)) { | |
966 | $output .= $contentpart; | |
967 | } | |
968 | ||
969 | // show availability info (if module is not available) | |
970 | $output .= $this->course_section_cm_availability($mod, $displayoptions); | |
971 | ||
972 | $output .= html_writer::end_tag('div'); // $indentclasses | |
973 | return $output; | |
974 | } | |
975 | ||
976 | /** | |
977 | * Renders HTML to display a list of course modules in a course section | |
978 | * Also displays "move here" controls in Javascript-disabled mode | |
979 | * | |
980 | * This function calls {@link core_course_renderer::course_section_cm()} | |
981 | * | |
982 | * @param stdClass $course course object | |
983 | * @param int|stdClass|section_info $section relative section number or section object | |
984 | * @param int $sectionreturn section number to return to | |
985 | * @param int $displayoptions | |
986 | * @return void | |
987 | */ | |
988 | public function course_section_cm_list($course, $section, $sectionreturn = null, $displayoptions = array()) { | |
989 | global $USER; | |
990 | ||
991 | $output = ''; | |
992 | $modinfo = get_fast_modinfo($course); | |
993 | if (is_object($section)) { | |
994 | $section = $modinfo->get_section_info($section->section); | |
995 | } else { | |
996 | $section = $modinfo->get_section_info($section); | |
997 | } | |
998 | $completioninfo = new completion_info($course); | |
999 | ||
1000 | // check if we are currently in the process of moving a module with JavaScript disabled | |
1001 | $ismoving = $this->page->user_is_editing() && ismoving($course->id); | |
1002 | if ($ismoving) { | |
1003 | $movingpix = new pix_icon('movehere', get_string('movehere'), 'moodle', array('class' => 'movetarget')); | |
1004 | $strmovefull = strip_tags(get_string("movefull", "", "'$USER->activitycopyname'")); | |
1005 | } | |
1006 | ||
1007 | // Get the list of modules visible to user (excluding the module being moved if there is one) | |
1008 | $moduleshtml = array(); | |
1009 | if (!empty($modinfo->sections[$section->section])) { | |
1010 | foreach ($modinfo->sections[$section->section] as $modnumber) { | |
1011 | $mod = $modinfo->cms[$modnumber]; | |
1012 | ||
1013 | if ($ismoving and $mod->id == $USER->activitycopy) { | |
1014 | // do not display moving mod | |
1015 | continue; | |
1016 | } | |
1017 | ||
1018 | if ($modulehtml = $this->course_section_cm($course, | |
1019 | $completioninfo, $mod, $sectionreturn, $displayoptions)) { | |
1020 | $moduleshtml[$modnumber] = $modulehtml; | |
1021 | } | |
1022 | } | |
1023 | } | |
1024 | ||
1025 | if (!empty($moduleshtml) || $ismoving) { | |
1026 | ||
1027 | $output .= html_writer::start_tag('ul', array('class' => 'section img-text')); | |
1028 | ||
1029 | foreach ($moduleshtml as $modnumber => $modulehtml) { | |
1030 | if ($ismoving) { | |
1031 | $movingurl = new moodle_url('/course/mod.php', array('moveto' => $modnumber, 'sesskey' => sesskey())); | |
1032 | $output .= html_writer::tag('li', html_writer::link($movingurl, $this->output->render($movingpix)), | |
1033 | array('class' => 'movehere', 'title' => $strmovefull)); | |
1034 | } | |
1035 | ||
1036 | $mod = $modinfo->cms[$modnumber]; | |
8df0765a | 1037 | $modclasses = 'activity '. $mod->modname. ' modtype_'.$mod->modname. ' '. $mod->get_extra_classes(); |
c58a25d6 MG |
1038 | $output .= html_writer::start_tag('li', array('class' => $modclasses, 'id' => 'module-'. $mod->id)); |
1039 | $output .= $modulehtml; | |
1040 | $output .= html_writer::end_tag('li'); | |
1041 | } | |
1042 | ||
1043 | if ($ismoving) { | |
1044 | $movingurl = new moodle_url('/course/mod.php', array('movetosection' => $section->id, 'sesskey' => sesskey())); | |
1045 | $output .= html_writer::tag('li', html_writer::link($movingurl, $this->output->render($movingpix)), | |
1046 | array('class' => 'movehere', 'title' => $strmovefull)); | |
1047 | } | |
1048 | ||
1049 | $output .= html_writer::end_tag('ul'); // .section | |
1050 | } | |
1051 | ||
1052 | return $output; | |
1053 | } | |
43e389ea | 1054 | |
9176cdb6 MG |
1055 | /** |
1056 | * Displays a custom list of courses with paging bar if necessary | |
1057 | * | |
1058 | * If $paginationurl is specified but $totalcount is not, the link 'View more' | |
1059 | * appears under the list. | |
1060 | * | |
1061 | * If both $paginationurl and $totalcount are specified, and $totalcount is | |
1062 | * bigger than count($courses), a paging bar is displayed above and under the | |
1063 | * courses list. | |
1064 | * | |
1065 | * @param array $courses array of course records (or instances of course_in_list) to show on this page | |
1066 | * @param bool $showcategoryname whether to add category name to the course description | |
1067 | * @param string $additionalclasses additional CSS classes to add to the div.courses | |
1068 | * @param moodle_url $paginationurl url to view more or url to form links to the other pages in paging bar | |
1069 | * @param int $totalcount total number of courses on all pages, if omitted $paginationurl will be displayed as 'View more' link | |
1070 | * @param int $page current page number (defaults to 0 referring to the first page) | |
1071 | * @param int $perpage number of records per page (defaults to $CFG->coursesperpage) | |
1072 | * @return string | |
1073 | */ | |
1074 | public function courses_list($courses, $showcategoryname = false, $additionalclasses = null, $paginationurl = null, $totalcount = null, $page = 0, $perpage = null) { | |
1075 | global $CFG; | |
1076 | // create instance of coursecat_helper to pass display options to function rendering courses list | |
1077 | $chelper = new coursecat_helper(); | |
1078 | if ($showcategoryname) { | |
1079 | $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED_WITH_CAT); | |
1080 | } else { | |
1081 | $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED); | |
1082 | } | |
1083 | if ($totalcount !== null && $paginationurl !== null) { | |
1084 | // add options to display pagination | |
1085 | if ($perpage === null) { | |
1086 | $perpage = $CFG->coursesperpage; | |
1087 | } | |
1088 | $chelper->set_courses_display_options(array( | |
1089 | 'limit' => $perpage, | |
1090 | 'offset' => ((int)$page) * $perpage, | |
1091 | 'paginationurl' => $paginationurl, | |
1092 | )); | |
1093 | } else if ($paginationurl !== null) { | |
1094 | // add options to display 'View more' link | |
1095 | $chelper->set_courses_display_options(array('viewmoreurl' => $paginationurl)); | |
1096 | $totalcount = count($courses) + 1; // has to be bigger than count($courses) otherwise link will not be displayed | |
1097 | } | |
1098 | $chelper->set_attributes(array('class' => $additionalclasses)); | |
1099 | $content = $this->coursecat_courses($chelper, $courses, $totalcount); | |
1100 | return $content; | |
1101 | } | |
1102 | ||
43e389ea MG |
1103 | /** |
1104 | * Displays one course in the list of courses. | |
1105 | * | |
1106 | * This is an internal function, to display an information about just one course | |
1107 | * please use {@link core_course_renderer::course_info_box()} | |
1108 | * | |
1109 | * @param coursecat_helper $chelper various display options | |
1110 | * @param course_in_list|stdClass $course | |
1111 | * @param string $additionalclasses additional classes to add to the main <div> tag (usually | |
1112 | * depend on the course position in list - first/last/even/odd) | |
1113 | * @return string | |
1114 | */ | |
1115 | protected function coursecat_coursebox(coursecat_helper $chelper, $course, $additionalclasses = '') { | |
1116 | global $CFG; | |
1117 | if (!isset($this->strings->summary)) { | |
1118 | $this->strings->summary = get_string('summary'); | |
1119 | } | |
1120 | if ($chelper->get_show_courses() <= self::COURSECAT_SHOW_COURSES_COUNT) { | |
1121 | return ''; | |
1122 | } | |
1123 | if ($course instanceof stdClass) { | |
1124 | require_once($CFG->libdir. '/coursecatlib.php'); | |
1125 | $course = new course_in_list($course); | |
1126 | } | |
1127 | $content = ''; | |
1128 | $classes = trim('coursebox clearfix '. $additionalclasses); | |
1129 | if ($chelper->get_show_courses() >= self::COURSECAT_SHOW_COURSES_EXPANDED) { | |
1130 | $nametag = 'h3'; | |
1131 | } else { | |
1132 | $classes .= ' collapsed'; | |
1133 | $nametag = 'div'; | |
1134 | } | |
1135 | $content .= html_writer::start_tag('div', array('class' => $classes)); // .coursebox | |
1136 | ||
1137 | $content .= html_writer::start_tag('div', array('class' => 'info')); | |
1138 | ||
1139 | // course name | |
1140 | $coursename = $chelper->get_course_formatted_name($course); | |
1141 | $coursenamelink = html_writer::link(new moodle_url('/course/view.php', array('id' => $course->id)), | |
1142 | $coursename, array('class' => $course->visible ? '' : 'dimmed')); | |
1143 | $content .= html_writer::tag($nametag, $coursenamelink, array('class' => 'name')); | |
1144 | ||
1145 | // If we display course in collapsed form but the course has summary or course contacts, display the link to the info page. | |
1146 | $content .= html_writer::start_tag('div', array('class' => 'moreinfo')); | |
1147 | if ($course->has_summary() || $course->has_course_contacts()) { | |
1148 | if ($chelper->get_show_courses() < self::COURSECAT_SHOW_COURSES_EXPANDED) { | |
1149 | $url = new moodle_url('/course/info.php', array('id' => $course->id)); | |
1150 | $image = html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/info'), | |
1151 | 'alt' => $this->strings->summary)); | |
1152 | $content .= $this->action_link($url, $image, new popup_action('click', $url, 'courseinfo'), | |
1153 | array('title' => $this->strings->summary)); | |
1154 | } | |
1155 | } | |
1156 | $content .= html_writer::end_tag('div'); // .moreinfo | |
1157 | ||
1158 | // print enrolmenticons | |
1159 | if ($icons = enrol_get_course_info_icons($course)) { | |
1160 | $content .= html_writer::start_tag('div', array('class' => 'enrolmenticons')); | |
1161 | foreach ($icons as $pix_icon) { | |
1162 | $content .= $this->render($pix_icon); | |
1163 | } | |
1164 | $content .= html_writer::end_tag('div'); // .enrolmenticons | |
1165 | } | |
1166 | ||
1167 | $content .= html_writer::end_tag('div'); // .info | |
1168 | ||
1169 | $content .= html_writer::start_tag('div', array('class' => 'content')); | |
1170 | $content .= $this->coursecat_coursebox_content($chelper, $course); | |
1171 | $content .= html_writer::end_tag('div'); // .content | |
1172 | ||
1173 | $content .= html_writer::end_tag('div'); // .coursebox | |
1174 | return $content; | |
1175 | } | |
1176 | ||
1177 | /** | |
1178 | * Returns HTML to display course content (summary, course contacts and optionally category name) | |
1179 | * | |
1180 | * This method is called from coursecat_coursebox() and may be re-used in AJAX | |
1181 | * | |
1182 | * @param coursecat_helper $chelper various display options | |
1183 | * @param stdClass|course_in_list $course | |
1184 | * @return string | |
1185 | */ | |
1186 | protected function coursecat_coursebox_content(coursecat_helper $chelper, $course) { | |
1187 | global $CFG; | |
1188 | if ($chelper->get_show_courses() < self::COURSECAT_SHOW_COURSES_EXPANDED) { | |
1189 | return ''; | |
1190 | } | |
1191 | if ($course instanceof stdClass) { | |
1192 | require_once($CFG->libdir. '/coursecatlib.php'); | |
1193 | $course = new course_in_list($course); | |
1194 | } | |
1195 | $content = ''; | |
1196 | ||
1197 | // display course summary | |
1198 | if ($course->has_summary()) { | |
1199 | $content .= html_writer::start_tag('div', array('class' => 'summary')); | |
1200 | $content .= $chelper->get_course_formatted_summary($course, | |
1201 | array('overflowdiv' => true, 'noclean' => true, 'para' => false)); | |
1202 | $content .= html_writer::end_tag('div'); // .summary | |
1203 | } | |
1204 | ||
1205 | // display course contacts. See course_in_list::get_course_contacts() | |
1206 | if ($course->has_course_contacts()) { | |
1207 | $content .= html_writer::start_tag('ul', array('class' => 'teachers')); | |
1208 | foreach ($course->get_course_contacts() as $userid => $coursecontact) { | |
1209 | $name = $coursecontact['rolename'].': '. | |
1210 | html_writer::link(new moodle_url('/user/view.php', | |
1211 | array('id' => $userid, 'course' => SITEID)), | |
1212 | $coursecontact['username']); | |
1213 | $content .= html_writer::tag('li', $name); | |
1214 | } | |
1215 | $content .= html_writer::end_tag('ul'); // .teachers | |
1216 | } | |
1217 | ||
1218 | // display course category if necessary (for example in search results) | |
1219 | if ($chelper->get_show_courses() == self::COURSECAT_SHOW_COURSES_EXPANDED_WITH_CAT | |
1220 | && ($cat = coursecat::get($course->category, IGNORE_MISSING))) { | |
1221 | $content .= html_writer::start_tag('div', array('class' => 'coursecat')); | |
1222 | $content .= get_string('category').': '. | |
1223 | html_writer::link(new moodle_url('/course/category.php', array('id' => $cat->id)), | |
1224 | $cat->get_formatted_name(), array('class' => $cat->visible ? '' : 'dimmed')); | |
1225 | $content .= html_writer::end_tag('div'); // .coursecat | |
1226 | } | |
1227 | ||
1228 | return $content; | |
1229 | } | |
1230 | ||
1231 | /** | |
1232 | * Renders the list of courses | |
1233 | * | |
1234 | * This is internal function, please use {@link core_course_renderer::courses_list()} or another public | |
1235 | * method from outside of the class | |
1236 | * | |
1237 | * If list of courses is specified in $courses; the argument $chelper is only used | |
1238 | * to retrieve display options and attributes, only methods get_show_courses(), | |
1239 | * get_courses_display_option() and get_and_erase_attributes() are called. | |
1240 | * | |
1241 | * @param coursecat_helper $chelper various display options | |
1242 | * @param array $courses the list of courses to display | |
1243 | * @param int|null $totalcount total number of courses (affects display mode if it is AUTO or pagination if applicable), | |
1244 | * defaulted to count($courses) | |
1245 | * @return string | |
1246 | */ | |
1247 | protected function coursecat_courses(coursecat_helper $chelper, $courses, $totalcount = null) { | |
1248 | global $CFG; | |
1249 | if ($totalcount === null) { | |
1250 | $totalcount = count($courses); | |
1251 | } | |
1252 | if (!$totalcount) { | |
1253 | // Courses count is cached during courses retrieval. | |
1254 | return ''; | |
1255 | } | |
1256 | ||
1257 | if ($chelper->get_show_courses() == self::COURSECAT_SHOW_COURSES_AUTO) { | |
1258 | // In 'auto' course display mode we analyse if number of courses is more or less than $CFG->courseswithsummarieslimit | |
1259 | if ($totalcount <= $CFG->courseswithsummarieslimit) { | |
1260 | $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_EXPANDED); | |
1261 | } else { | |
1262 | $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_COLLAPSED); | |
1263 | } | |
1264 | } | |
1265 | ||
1266 | // prepare content of paging bar if it is needed | |
1267 | $paginationurl = $chelper->get_courses_display_option('paginationurl'); | |
1268 | $paginationallowall = $chelper->get_courses_display_option('paginationallowall'); | |
1269 | if ($totalcount > count($courses)) { | |
1270 | // there are more results that can fit on one page | |
1271 | if ($paginationurl) { | |
1272 | // the option paginationurl was specified, display pagingbar | |
1273 | $perpage = $chelper->get_courses_display_option('limit', $CFG->coursesperpage); | |
1274 | $page = $chelper->get_courses_display_option('offset') / $perpage; | |
1275 | $pagingbar = $this->paging_bar($totalcount, $page, $perpage, | |
1276 | $paginationurl->out(false, array('perpage' => $perpage))); | |
1277 | if ($paginationallowall) { | |
1278 | $pagingbar .= html_writer::tag('div', html_writer::link($paginationurl->out(false, array('perpage' => 'all')), | |
1279 | get_string('showall', '', $totalcount)), array('class' => 'paging paging-showall')); | |
1280 | } | |
1281 | } else if ($viewmoreurl = $chelper->get_courses_display_option('viewmoreurl')) { | |
1282 | // the option for 'View more' link was specified, display more link | |
1283 | $viewmoretext = $chelper->get_courses_display_option('viewmoretext', new lang_string('viewmore')); | |
1284 | $morelink = html_writer::tag('div', html_writer::link($viewmoreurl, $viewmoretext), | |
1285 | array('class' => 'paging paging-morelink')); | |
1286 | } | |
1287 | } else if (($totalcount > $CFG->coursesperpage) && $paginationurl && $paginationallowall) { | |
1288 | // there are more than one page of results and we are in 'view all' mode, suggest to go back to paginated view mode | |
1289 | $pagingbar = html_writer::tag('div', html_writer::link($paginationurl->out(false, array('perpage' => $CFG->coursesperpage)), | |
1290 | get_string('showperpage', '', $CFG->coursesperpage)), array('class' => 'paging paging-showperpage')); | |
1291 | } | |
1292 | ||
1293 | // display list of courses | |
1294 | $attributes = $chelper->get_and_erase_attributes('courses'); | |
1295 | $content = html_writer::start_tag('div', $attributes); | |
1296 | ||
1297 | if (!empty($pagingbar)) { | |
1298 | $content .= $pagingbar; | |
1299 | } | |
1300 | ||
1301 | $coursecount = 0; | |
1302 | foreach ($courses as $course) { | |
1303 | $coursecount ++; | |
1304 | $classes = ($coursecount%2) ? 'odd' : 'even'; | |
1305 | if ($coursecount == 1) { | |
1306 | $classes .= ' first'; | |
1307 | } | |
1308 | if ($coursecount >= count($courses)) { | |
1309 | $classes .= ' last'; | |
1310 | } | |
1311 | $content .= $this->coursecat_coursebox($chelper, $course, $classes); | |
1312 | } | |
1313 | ||
1314 | if (!empty($pagingbar)) { | |
1315 | $content .= $pagingbar; | |
1316 | } | |
1317 | if (!empty($morelink)) { | |
1318 | $content .= $morelink; | |
1319 | } | |
1320 | ||
1321 | $content .= html_writer::end_tag('div'); // .courses | |
1322 | return $content; | |
1323 | } | |
1324 | ||
1325 | /** | |
1326 | * Renders the list of subcategories in a category | |
1327 | * | |
1328 | * @param coursecat_helper $chelper various display options | |
1329 | * @param coursecat $coursecat | |
1330 | * @param int $depth depth of the category in the current tree | |
1331 | * @return string | |
1332 | */ | |
1333 | protected function coursecat_subcategories(coursecat_helper $chelper, $coursecat, $depth) { | |
1334 | global $CFG; | |
1335 | $subcategories = array(); | |
1336 | if (!$chelper->get_categories_display_option('nodisplay')) { | |
1337 | $subcategories = $coursecat->get_children($chelper->get_categories_display_options()); | |
1338 | } | |
1339 | $totalcount = $coursecat->get_children_count(); | |
1340 | if (!$totalcount) { | |
1341 | // Note that we call get_child_categories_count() AFTER get_child_categories() to avoid extra DB requests. | |
1342 | // Categories count is cached during children categories retrieval. | |
1343 | return ''; | |
1344 | } | |
1345 | ||
1346 | // prepare content of paging bar or more link if it is needed | |
1347 | $paginationurl = $chelper->get_categories_display_option('paginationurl'); | |
1348 | $paginationallowall = $chelper->get_categories_display_option('paginationallowall'); | |
1349 | if ($totalcount > count($subcategories)) { | |
1350 | if ($paginationurl) { | |
1351 | // the option 'paginationurl was specified, display pagingbar | |
1352 | $perpage = $chelper->get_categories_display_option('limit', $CFG->coursesperpage); | |
1353 | $page = $chelper->get_categories_display_option('offset') / $perpage; | |
1354 | $pagingbar = $this->paging_bar($totalcount, $page, $perpage, | |
1355 | $paginationurl->out(false, array('perpage' => $perpage))); | |
1356 | if ($paginationallowall) { | |
1357 | $pagingbar .= html_writer::tag('div', html_writer::link($paginationurl->out(false, array('perpage' => 'all')), | |
1358 | get_string('showall', '', $totalcount)), array('class' => 'paging paging-showall')); | |
1359 | } | |
1360 | } else if ($viewmoreurl = $chelper->get_categories_display_option('viewmoreurl')) { | |
1361 | // the option 'viewmoreurl' was specified, display more link (if it is link to category view page, add category id) | |
1362 | if ($viewmoreurl->compare(new moodle_url('/course/category.php'), URL_MATCH_BASE)) { | |
1363 | if ($coursecat->id) { | |
1364 | $viewmoreurl->param('id', $coursecat->id); | |
1365 | } else { | |
1366 | $viewmoreurl = new moodle_url('/course/index.php', $viewmoreurl->params()); | |
1367 | } | |
1368 | } | |
1369 | $viewmoretext = $chelper->get_categories_display_option('viewmoretext', new lang_string('viewmore')); | |
1370 | $morelink = html_writer::tag('div', html_writer::link($viewmoreurl, $viewmoretext), | |
1371 | array('class' => 'paging paging-morelink')); | |
1372 | } | |
1373 | } else if (($totalcount > $CFG->coursesperpage) && $paginationurl && $paginationallowall) { | |
1374 | // there are more than one page of results and we are in 'view all' mode, suggest to go back to paginated view mode | |
1375 | $pagingbar = html_writer::tag('div', html_writer::link($paginationurl->out(false, array('perpage' => $CFG->coursesperpage)), | |
1376 | get_string('showperpage', '', $CFG->coursesperpage)), array('class' => 'paging paging-showperpage')); | |
1377 | } | |
1378 | ||
1379 | // display list of subcategories | |
1380 | $content = html_writer::start_tag('div', array('class' => 'subcategories')); | |
1381 | ||
1382 | if (!empty($pagingbar)) { | |
1383 | $content .= $pagingbar; | |
1384 | } | |
1385 | ||
1386 | foreach ($subcategories as $subcategory) { | |
1387 | $content .= $this->coursecat_category($chelper, $subcategory, $depth + 1); | |
1388 | } | |
1389 | ||
1390 | if (!empty($pagingbar)) { | |
1391 | $content .= $pagingbar; | |
1392 | } | |
1393 | if (!empty($morelink)) { | |
1394 | $content .= $morelink; | |
1395 | } | |
1396 | ||
1397 | $content .= html_writer::end_tag('div'); | |
1398 | return $content; | |
1399 | } | |
1400 | ||
1401 | /** | |
1402 | * Returns HTML to display the subcategories and courses in the given category | |
1403 | * | |
1404 | * This method is re-used by AJAX to expand content of not loaded category | |
1405 | * | |
1406 | * @param coursecat_helper $chelper various display options | |
1407 | * @param coursecat $coursecat | |
1408 | * @param int $depth depth of the category in the current tree | |
1409 | * @return string | |
1410 | */ | |
1411 | protected function coursecat_category_content(coursecat_helper $chelper, $coursecat, $depth) { | |
1412 | $content = ''; | |
1413 | // Subcategories | |
1414 | $content .= $this->coursecat_subcategories($chelper, $coursecat, $depth); | |
1415 | ||
1416 | // AUTO show courses: Courses will be shown expanded if this is not nested category, | |
1417 | // and number of courses no bigger than $CFG->courseswithsummarieslimit. | |
1418 | $showcoursesauto = $chelper->get_show_courses() == self::COURSECAT_SHOW_COURSES_AUTO; | |
1419 | if ($showcoursesauto && $depth) { | |
1420 | // this is definitely collapsed mode | |
1421 | $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_COLLAPSED); | |
1422 | } | |
1423 | ||
1424 | // Courses | |
1425 | if ($chelper->get_show_courses() > core_course_renderer::COURSECAT_SHOW_COURSES_COUNT) { | |
1426 | $courses = $coursecat->get_courses($chelper->get_courses_display_options()); | |
1427 | if ($viewmoreurl = $chelper->get_courses_display_option('viewmoreurl')) { | |
1428 | // the option for 'View more' link was specified, display more link (if it is link to category view page, add category id) | |
1429 | if ($viewmoreurl->compare(new moodle_url('/course/category.php'), URL_MATCH_BASE)) { | |
1430 | $chelper->set_courses_display_option('viewmoreurl', new moodle_url($viewmoreurl, array('id' => $coursecat->id))); | |
1431 | } | |
1432 | } | |
1433 | $content .= $this->coursecat_courses($chelper, $courses, $coursecat->get_courses_count()); | |
1434 | } | |
1435 | ||
1436 | if ($showcoursesauto) { | |
1437 | // restore the show_courses back to AUTO | |
1438 | $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_AUTO); | |
1439 | } | |
1440 | ||
1441 | return $content; | |
1442 | } | |
1443 | ||
1444 | /** | |
1445 | * Returns HTML to display a course category as a part of a tree | |
1446 | * | |
1447 | * This is an internal function, to display a particular category and all its contents | |
1448 | * use {@link core_course_renderer::course_category()} | |
1449 | * | |
1450 | * @param coursecat_helper $chelper various display options | |
1451 | * @param coursecat $coursecat | |
1452 | * @param int $depth depth of this category in the current tree | |
1453 | * @return string | |
1454 | */ | |
1455 | protected function coursecat_category(coursecat_helper $chelper, $coursecat, $depth) { | |
1456 | // open category tag | |
1457 | $classes = array('category'); | |
1458 | if (empty($coursecat->visible)) { | |
1459 | $classes[] = 'dimmed_category'; | |
1460 | } | |
1461 | if ($chelper->get_subcat_depth() > 0 && $depth >= $chelper->get_subcat_depth()) { | |
1462 | // do not load content | |
1463 | $categorycontent = ''; | |
1464 | $classes[] = 'notloaded'; | |
1465 | if ($coursecat->get_children_count() || | |
1466 | ($chelper->get_show_courses() >= self::COURSECAT_SHOW_COURSES_COLLAPSED && $coursecat->get_courses_count())) { | |
1467 | $classes[] = 'with_children'; | |
1468 | $classes[] = 'collapsed'; | |
1469 | } | |
1470 | } else { | |
1471 | // load category content | |
1472 | $categorycontent = $this->coursecat_category_content($chelper, $coursecat, $depth); | |
1473 | $classes[] = 'loaded'; | |
1474 | if (!empty($categorycontent)) { | |
1475 | $classes[] = 'with_children'; | |
1476 | } | |
1477 | } | |
1478 | $content = html_writer::start_tag('div', array('class' => join(' ', $classes), | |
1479 | 'data-categoryid' => $coursecat->id, | |
1480 | 'data-depth' => $depth)); | |
1481 | ||
1482 | // category name | |
1483 | $categoryname = $coursecat->get_formatted_name(); | |
1484 | $categoryname = html_writer::link(new moodle_url('/course/category.php', | |
1485 | array('id' => $coursecat->id)), | |
1486 | $categoryname); | |
1487 | if ($chelper->get_show_courses() == self::COURSECAT_SHOW_COURSES_COUNT | |
1488 | && ($coursescount = $coursecat->get_courses_count())) { | |
1489 | $categoryname .= html_writer::tag('span', ' ('. $coursescount.')', | |
1490 | array('title' => get_string('numberofcourses'), 'class' => 'numberofcourse')); | |
1491 | } | |
1492 | $content .= html_writer::start_tag('div', array('class' => 'info')); | |
1493 | $content .= html_writer::tag(($depth > 1) ? 'h4' : 'h3', $categoryname, array('class' => 'name')); | |
1494 | $content .= html_writer::end_tag('div'); // .info | |
1495 | ||
1496 | // add category content to the output | |
1497 | $content .= html_writer::tag('div', $categorycontent, array('class' => 'content')); | |
1498 | ||
1499 | $content .= html_writer::end_tag('div'); // .category | |
1500 | ||
1501 | // Return the course category tree HTML | |
1502 | return $content; | |
1503 | } | |
1504 | ||
1505 | /** | |
1506 | * Returns HTML to display a tree of subcategories and courses in the given category | |
1507 | * | |
1508 | * @param coursecat_helper $chelper various display options | |
1509 | * @param coursecat $coursecat top category (this category's name and description will NOT be added to the tree) | |
1510 | * @return string | |
1511 | */ | |
1512 | protected function coursecat_tree(coursecat_helper $chelper, $coursecat) { | |
1513 | $categorycontent = $this->coursecat_category_content($chelper, $coursecat, 0); | |
1514 | if (empty($categorycontent)) { | |
1515 | return ''; | |
1516 | } | |
1517 | ||
1518 | // Generate an id and the required JS call to make this a nice widget | |
1519 | $id = html_writer::random_id('course_category_tree'); | |
1520 | $this->page->requires->js_init_call('M.util.init_toggle_class_on_click', | |
1521 | array($id, '.category.with_children.loaded > .info .name', 'collapsed', '.category.with_children.loaded')); | |
1522 | ||
1523 | // Start content generation | |
1524 | $content = ''; | |
1525 | $attributes = $chelper->get_and_erase_attributes('course_category_tree clearfix'); | |
1526 | $content .= html_writer::start_tag('div', | |
1527 | array('id' => $id, 'data-showcourses' => $chelper->get_show_courses()) + $attributes); | |
1528 | ||
1529 | $content .= html_writer::tag('div', $categorycontent, array('class' => 'content')); | |
1530 | ||
1531 | if ($coursecat->get_children_count() && $chelper->get_subcat_depth() != 1) { | |
1532 | // We don't need to display "Expand all"/"Collapse all" buttons if there are no | |
1533 | // subcategories or there is only one level of subcategories loaded | |
1534 | // TODO if subcategories are loaded by AJAX this might still be needed! | |
1535 | $content .= html_writer::start_tag('div', array('class' => 'controls')); | |
1536 | $content .= html_writer::tag('div', get_string('collapseall'), array('class' => 'addtoall expandall')); | |
1537 | $content .= html_writer::tag('div', get_string('expandall'), array('class' => 'removefromall collapseall')); | |
1538 | $content .= html_writer::end_tag('div'); | |
1539 | } | |
1540 | ||
1541 | $content .= html_writer::end_tag('div'); // .course_category_tree | |
1542 | ||
1543 | return $content; | |
1544 | } | |
8e57a6df MG |
1545 | |
1546 | /** | |
1547 | * Renders HTML to display particular course category - list of it's subcategories and courses | |
1548 | * | |
1549 | * Invoked from /course/index.php | |
1550 | * | |
1551 | * @param int|stdClass|coursecat $category | |
1552 | */ | |
1553 | public function course_category($category) { | |
1554 | global $CFG; | |
1555 | require_once($CFG->libdir. '/coursecatlib.php'); | |
1556 | $coursecat = coursecat::get(is_object($category) ? $category->id : $category); | |
1557 | $site = get_site(); | |
1558 | $output = ''; | |
1559 | ||
1560 | if (!$coursecat->id && coursecat::count_all() == 1) { | |
1561 | // There exists only one category in the system, do not display link to it | |
1562 | $coursecat = coursecat::get_default(); | |
1563 | $strfulllistofcourses = get_string('fulllistofcourses'); | |
1564 | $this->page->set_title("$site->shortname: $strfulllistofcourses"); | |
1565 | } else if (!$coursecat->id) { | |
1566 | $strcategories = get_string('categories'); | |
1567 | $this->page->set_title("$site->shortname: $strcategories"); | |
1568 | } else { | |
1569 | $this->page->set_title("$site->shortname: ". $coursecat->get_formatted_name()); | |
1570 | $this->page->set_button($this->course_search_form('', 'navbar')); | |
1571 | ||
1572 | // Print the category selector | |
1573 | $output .= html_writer::start_tag('div', array('class' => 'categorypicker')); | |
1574 | $select = new single_select(new moodle_url('/course/category.php'), 'id', | |
1575 | coursecat::make_categories_list(), $coursecat->id, null, 'switchcategory'); | |
1576 | $select->set_label(get_string('categories').':'); | |
1577 | $output .= $this->render($select); | |
1578 | $output .= html_writer::end_tag('div'); // .categorypicker | |
1579 | } | |
1580 | ||
1581 | // Print current category description | |
1582 | $chelper = new coursecat_helper(); | |
1583 | if ($description = $chelper->get_category_formatted_description($coursecat)) { | |
1584 | $output .= $this->box($description, array('class' => 'generalbox info')); | |
1585 | } | |
1586 | ||
1587 | // Prepare parameters for courses and categories lists in the tree | |
1588 | $chelper->set_show_courses(self::COURSECAT_SHOW_COURSES_AUTO) | |
1589 | ->set_attributes(array('class' => 'category-browse category-browse-'.$coursecat->id)); | |
1590 | ||
1591 | $coursedisplayoptions = array(); | |
1592 | $catdisplayoptions = array(); | |
1593 | $browse = optional_param('browse', null, PARAM_ALPHA); | |
1594 | $perpage = optional_param('perpage', $CFG->coursesperpage, PARAM_INT); | |
1595 | $page = optional_param('page', 0, PARAM_INT); | |
1596 | if ($coursecat->id) { | |
1597 | $baseurl = new moodle_url('/course/category.php', array('id' => $coursecat->id)); | |
1598 | } else { | |
1599 | $baseurl = new moodle_url('/course/index.php'); | |
1600 | } | |
1601 | if ($browse === 'courses' || !$coursecat->has_children()) { | |
1602 | $coursedisplayoptions['limit'] = $perpage; | |
1603 | $coursedisplayoptions['offset'] = $page * $perpage; | |
1604 | $coursedisplayoptions['paginationurl'] = new moodle_url($baseurl, array('browse' => 'courses', 'perpage' => $perpage)); | |
1605 | $catdisplayoptions['nodisplay'] = true; | |
1606 | $catdisplayoptions['viewmoreurl'] = new moodle_url($baseurl, array('browse' => 'categories', 'page' => 0)); | |
1607 | $catdisplayoptions['viewmoretext'] = new lang_string('viewallsubcategores'); | |
1608 | } else if ($browse === 'categories' || !$coursecat->has_courses()) { | |
1609 | $coursedisplayoptions['nodisplay'] = true; | |
1610 | $catdisplayoptions['limit'] = $perpage; | |
1611 | $catdisplayoptions['offset'] = $page * $perpage; | |
1612 | $catdisplayoptions['paginationurl'] = new moodle_url($baseurl, array('browse' => 'categories', 'perpage' => $perpage)); | |
1613 | $coursedisplayoptions['viewmoreurl'] = new moodle_url($baseurl, array('browse' => 'courses', 'page' => 0)); | |
1614 | $coursedisplayoptions['viewmoretext'] = new lang_string('viewallcourses'); | |
1615 | } else { | |
1616 | // we have a category that has both subcategories and courses, display pagination separately | |
1617 | $coursedisplayoptions['limit'] = $CFG->coursesperpage; | |
1618 | $catdisplayoptions['limit'] = $CFG->coursesperpage; | |
1619 | $coursedisplayoptions['viewmoreurl'] = new moodle_url($baseurl, array('browse' => 'courses', 'page' => 1)); | |
1620 | $catdisplayoptions['viewmoreurl'] = new moodle_url($baseurl, array('browse' => 'categories', 'page' => 1)); | |
1621 | } | |
1622 | $chelper->set_courses_display_options($coursedisplayoptions)->set_categories_display_options($catdisplayoptions); | |
1623 | ||
1624 | // Display course category tree | |
1625 | $output .= $this->coursecat_tree($chelper, $coursecat); | |
1626 | ||
1627 | // Add course search form (if we are inside category it was already added to the navbar) | |
1628 | if (!$coursecat->id) { | |
1629 | $output .= $this->course_search_form(); | |
1630 | } | |
1631 | ||
1632 | // Add action buttons | |
1633 | $output .= $this->container_start('buttons'); | |
1634 | $context = get_category_or_system_context($coursecat->id); | |
1635 | if (has_capability('moodle/course:create', $context)) { | |
1636 | // Print link to create a new course, for the 1st available category. | |
1637 | if ($coursecat->id) { | |
1638 | $url = new moodle_url('/course/edit.php', array('category' => $coursecat->id, 'returnto' => 'category')); | |
1639 | } else { | |
1640 | $url = new moodle_url('/course/edit.php', array('category' => $CFG->defaultrequestcategory, 'returnto' => 'topcat')); | |
1641 | } | |
1642 | $output .= $this->single_button($url, get_string('addnewcourse'), 'get'); | |
1643 | } | |
1644 | ob_start(); | |
1645 | if (coursecat::count_all() == 1) { | |
1646 | print_course_request_buttons(context_system::instance()); | |
1647 | } else { | |
1648 | print_course_request_buttons($context); | |
1649 | } | |
1650 | $output .= ob_get_contents(); | |
1651 | ob_end_clean(); | |
1652 | $output .= $this->container_end(); | |
1653 | ||
1654 | return $output; | |
1655 | } | |
43e389ea MG |
1656 | } |
1657 | ||
1658 | /** | |
1659 | * Class storing display options and functions to help display course category and/or courses lists | |
1660 | * | |
1661 | * This is a wrapper for coursecat objects that also stores display options | |
1662 | * and functions to retrieve sorted and paginated lists of categories/courses. | |
1663 | * | |
1664 | * If theme overrides methods in core_course_renderers that access this class | |
1665 | * it may as well not use this class at all or extend it. | |
1666 | * | |
1667 | * @package core | |
1668 | * @copyright 2013 Marina Glancy | |
1669 | * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later | |
1670 | */ | |
1671 | class coursecat_helper { | |
1672 | /** @var string [none, collapsed, expanded] how (if) display courses list */ | |
1673 | protected $showcourses = 10; /* core_course_renderer::COURSECAT_SHOW_COURSES_COLLAPSED */ | |
1674 | /** @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) */ | |
1675 | protected $subcatdepth = 1; | |
1676 | /** @var array options to display courses list */ | |
1677 | protected $coursesdisplayoptions = array(); | |
1678 | /** @var array options to display subcategories list */ | |
1679 | protected $categoriesdisplayoptions = array(); | |
1680 | /** @var array additional HTML attributes */ | |
1681 | protected $attributes = array(); | |
1682 | /** @var array search criteria if the list is a search result */ | |
1683 | protected $searchcriteria = null; | |
1684 | ||
1685 | /** | |
1686 | * Sets how (if) to show the courses - none, collapsed, expanded, etc. | |
1687 | * | |
1688 | * @param int $showcourses SHOW_COURSES_NONE, SHOW_COURSES_COLLAPSED, SHOW_COURSES_EXPANDED, etc. | |
1689 | * @return coursecat_helper | |
1690 | */ | |
1691 | public function set_show_courses($showcourses) { | |
1692 | $this->showcourses = $showcourses; | |
1693 | // Automatically set the options to preload summary and coursecontacts for coursecat::get_courses() and coursecat::search_courses() | |
1694 | $this->coursesdisplayoptions['summary'] = $showcourses >= core_course_renderer::COURSECAT_SHOW_COURSES_AUTO; | |
1695 | $this->coursesdisplayoptions['coursecontacts'] = $showcourses >= core_course_renderer::COURSECAT_SHOW_COURSES_EXPANDED; | |
1696 | return $this; | |
1697 | } | |
1698 | ||
1699 | /** | |
1700 | * Returns how (if) to show the courses - none, collapsed, expanded, etc. | |
1701 | * | |
1702 | * @return int - COURSECAT_SHOW_COURSES_NONE, COURSECAT_SHOW_COURSES_COLLAPSED, COURSECAT_SHOW_COURSES_EXPANDED, etc. | |
1703 | */ | |
1704 | public function get_show_courses() { | |
1705 | return $this->showcourses; | |
1706 | } | |
1707 | ||
1708 | /** | |
1709 | * Sets the maximum depth to expand subcategories in the tree | |
1710 | * | |
1711 | * deeper subcategories may be loaded by AJAX or proceed to category page by clicking on category name | |
1712 | * | |
1713 | * @param int $subcatdepth | |
1714 | * @return coursecat_helper | |
1715 | */ | |
1716 | public function set_subcat_depth($subcatdepth) { | |
1717 | $this->subcatdepth = $subcatdepth; | |
1718 | return $this; | |
1719 | } | |
1720 | ||
1721 | /** | |
1722 | * Returns the maximum depth to expand subcategories in the tree | |
1723 | * | |
1724 | * deeper subcategories may be loaded by AJAX or proceed to category page by clicking on category name | |
1725 | * | |
1726 | * @return int | |
1727 | */ | |
1728 | public function get_subcat_depth() { | |
1729 | return $this->subcatdepth; | |
1730 | } | |
1731 | ||
1732 | /** | |
1733 | * Sets options to display list of courses | |
1734 | * | |
1735 | * Options are later submitted as argument to coursecat::get_courses() and/or coursecat::search_courses() | |
1736 | * | |
1737 | * Options that coursecat::get_courses() accept: | |
1738 | * - recursive - return courses from subcategories as well. Use with care, | |
1739 | * this may be a huge list! | |
1740 | * - summary - preloads fields 'summary' and 'summaryformat' | |
1741 | * - coursecontacts - preloads course contacts | |
1742 | * - isenrolled - preloads indication whether this user is enrolled in the course | |
1743 | * - sort - list of fields to sort. Example | |
1744 | * array('idnumber' => 1, 'shortname' => 1, 'id' => -1) | |
1745 | * will sort by idnumber asc, shortname asc and id desc. | |
1746 | * Default: array('sortorder' => 1) | |
1747 | * Only cached fields may be used for sorting! | |
1748 | * - offset | |
1749 | * - limit - maximum number of children to return, 0 or null for no limit | |
1750 | * | |
1751 | * Options summary and coursecontacts are filled automatically in the set_show_courses() | |
1752 | * | |
1753 | * Also renderer can set here any additional options it wants to pass between renderer functions. | |
1754 | * | |
1755 | * @param array $options | |
1756 | * @return coursecat_helper | |
1757 | */ | |
1758 | public function set_courses_display_options($options) { | |
1759 | $this->coursesdisplayoptions = $options; | |
1760 | $this->set_show_courses($this->showcourses); // this will calculate special display options | |
1761 | return $this; | |
1762 | } | |
1763 | ||
1764 | /** | |
1765 | * Sets one option to display list of courses | |
1766 | * | |
1767 | * @see coursecat_helper::set_courses_display_options() | |
1768 | * | |
1769 | * @param string $key | |
1770 | * @param mixed $value | |
1771 | * @return coursecat_helper | |
1772 | */ | |
1773 | public function set_courses_display_option($key, $value) { | |
1774 | $this->coursesdisplayoptions[$key] = $value; | |
1775 | return $this; | |
1776 | } | |
1777 | ||
1778 | /** | |
1779 | * Return the specified option to display list of courses | |
1780 | * | |
1781 | * @param string $optionname option name | |
1782 | * @param mixed $defaultvalue default value for option if it is not specified | |
1783 | * @return mixed | |
1784 | */ | |
1785 | public function get_courses_display_option($optionname, $defaultvalue = null) { | |
1786 | if (array_key_exists($optionname, $this->coursesdisplayoptions)) { | |
1787 | return $this->coursesdisplayoptions[$optionname]; | |
1788 | } else { | |
1789 | return $defaultvalue; | |
1790 | } | |
1791 | } | |
1792 | ||
1793 | /** | |
1794 | * Returns all options to display the courses | |
1795 | * | |
1796 | * This array is usually passed to {@link coursecat::get_courses()} or | |
1797 | * {@link coursecat::search_courses()} | |
1798 | * | |
1799 | * @return array | |
1800 | */ | |
1801 | public function get_courses_display_options() { | |
1802 | return $this->coursesdisplayoptions; | |
1803 | } | |
1804 | ||
1805 | /** | |
1806 | * Sets options to display list of subcategories | |
1807 | * | |
1808 | * Options 'sort', 'offset' and 'limit' are passed to coursecat::get_children(). | |
1809 | * Any other options may be used by renderer functions | |
1810 | * | |
1811 | * @param array $options | |
1812 | * @return coursecat_helper | |
1813 | */ | |
1814 | public function set_categories_display_options($options) { | |
1815 | $this->categoriesdisplayoptions = $options; | |
1816 | return $this; | |
1817 | } | |
1818 | ||
1819 | /** | |
1820 | * Return the specified option to display list of subcategories | |
1821 | * | |
1822 | * @param string $optionname option name | |
1823 | * @param mixed $defaultvalue default value for option if it is not specified | |
1824 | * @return mixed | |
1825 | */ | |
1826 | public function get_categories_display_option($optionname, $defaultvalue = null) { | |
1827 | if (array_key_exists($optionname, $this->categoriesdisplayoptions)) { | |
1828 | return $this->categoriesdisplayoptions[$optionname]; | |
1829 | } else { | |
1830 | return $defaultvalue; | |
1831 | } | |
1832 | } | |
1833 | ||
1834 | /** | |
1835 | * Returns all options to display list of subcategories | |
1836 | * | |
1837 | * This array is usually passed to {@link coursecat::get_children()} | |
1838 | * | |
1839 | * @return array | |
1840 | */ | |
1841 | public function get_categories_display_options() { | |
1842 | return $this->categoriesdisplayoptions; | |
1843 | } | |
1844 | ||
1845 | /** | |
1846 | * Sets additional general options to pass between renderer functions, usually HTML attributes | |
1847 | * | |
1848 | * @param array $attributes | |
1849 | * @return coursecat_helper | |
1850 | */ | |
1851 | public function set_attributes($attributes) { | |
1852 | $this->attributes = $attributes; | |
1853 | return $this; | |
1854 | } | |
1855 | ||
1856 | /** | |
1857 | * Return all attributes and erases them so they are not applied again | |
1858 | * | |
1859 | * @param string $classname adds additional class name to the beginning of $attributes['class'] | |
1860 | * @return array | |
1861 | */ | |
1862 | public function get_and_erase_attributes($classname) { | |
1863 | $attributes = $this->attributes; | |
1864 | $this->attributes = array(); | |
1865 | if (empty($attributes['class'])) { | |
1866 | $attributes['class'] = ''; | |
1867 | } | |
1868 | $attributes['class'] = $classname . ' '. $attributes['class']; | |
1869 | return $attributes; | |
1870 | } | |
1871 | ||
1872 | /** | |
1873 | * Sets the search criteria if the course is a search result | |
1874 | * | |
1875 | * Search string will be used to highlight terms in course name and description | |
1876 | * | |
1877 | * @param array $searchcriteria | |
1878 | * @return coursecat_helper | |
1879 | */ | |
1880 | public function set_search_criteria($searchcriteria) { | |
1881 | $this->searchcriteria = $searchcriteria; | |
1882 | return $this; | |
1883 | } | |
1884 | ||
1885 | /** | |
1886 | * Returns formatted and filtered description of the given category | |
1887 | * | |
1888 | * @param coursecat $coursecat category | |
1889 | * @param stdClass|array $options format options, by default [noclean,overflowdiv], | |
1890 | * if context is not specified it will be added automatically | |
1891 | * @return string|null | |
1892 | */ | |
1893 | public function get_category_formatted_description($coursecat, $options = null) { | |
1894 | if ($coursecat->id && !empty($coursecat->description)) { | |
1895 | if (!isset($coursecat->descriptionformat)) { | |
1896 | $descriptionformat = FORMAT_MOODLE; | |
1897 | } else { | |
1898 | $descriptionformat = $coursecat->descriptionformat; | |
1899 | } | |
1900 | if ($options === null) { | |
1901 | $options = array('noclean' => true, 'overflowdiv' => true); | |
1902 | } else { | |
1903 | $options = (array)$options; | |
1904 | } | |
1905 | $context = context_coursecat::instance($coursecat->id); | |
1906 | if (!isset($options['context'])) { | |
1907 | $options['context'] = $context; | |
1908 | } | |
1909 | $text = file_rewrite_pluginfile_urls($coursecat->description, | |
1910 | 'pluginfile.php', $context->id, 'coursecat', 'description', null); | |
1911 | return format_text($text, $descriptionformat, $options); | |
1912 | } | |
1913 | return null; | |
1914 | } | |
1915 | ||
1916 | /** | |
1917 | * Returns given course's summary with proper embedded files urls and formatted | |
1918 | * | |
1919 | * @param course_in_list $course | |
1920 | * @param array|stdClass $options additional formatting options | |
1921 | * @return string | |
1922 | */ | |
1923 | public function get_course_formatted_summary($course, $options = array()) { | |
1924 | global $CFG; | |
1925 | require_once($CFG->libdir. '/filelib.php'); | |
1926 | if (!$course->has_summary()) { | |
1927 | return ''; | |
1928 | } | |
1929 | $options = (array)$options; | |
1930 | $context = context_course::instance($course->id); | |
1931 | if (!isset($options['context'])) { | |
1932 | // TODO see MDL-38521 | |
1933 | // option 1 (current), page context - no code required | |
1934 | // option 2, system context | |
1935 | // $options['context'] = context_system::instance(); | |
1936 | // option 3, course context: | |
1937 | // $options['context'] = $context; | |
1938 | // option 4, course category context: | |
1939 | // $options['context'] = $context->get_parent_context(); | |
1940 | } | |
1941 | $summary = file_rewrite_pluginfile_urls($course->summary, 'pluginfile.php', $context->id, 'course', 'summary', null); | |
1942 | $summary = format_text($summary, $course->summaryformat, $options, $course->id); | |
1943 | if (!empty($this->searchcriteria['search'])) { | |
1944 | $summary = highlight($this->searchcriteria['search'], $summary); | |
1945 | } | |
1946 | return $summary; | |
1947 | } | |
1948 | ||
1949 | /** | |
1950 | * Returns course name as it is configured to appear in courses lists formatted to course context | |
1951 | * | |
1952 | * @param course_in_list $course | |
1953 | * @param array|stdClass $options additional formatting options | |
1954 | * @return string | |
1955 | */ | |
1956 | public function get_course_formatted_name($course, $options = array()) { | |
1957 | $options = (array)$options; | |
1958 | if (!isset($options['context'])) { | |
1959 | $options['context'] = context_course::instance($course->id); | |
1960 | } | |
1961 | $name = format_string(get_course_display_name_for_list($course), true, $options); | |
1962 | if (!empty($this->searchcriteria['search'])) { | |
1963 | $name = highlight($this->searchcriteria['search'], $name); | |
1964 | } | |
1965 | return $name; | |
1966 | } | |
f4c23f03 | 1967 | } |