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