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 { | |
36 | ||
37 | /** | |
38 | * A cache of strings | |
39 | * @var stdClass | |
40 | */ | |
41 | protected $strings; | |
42 | ||
43 | /** | |
44 | * Override the constructor so that we can initialise the string cache | |
45 | * | |
46 | * @param moodle_page $page | |
47 | * @param string $target | |
48 | */ | |
49 | public function __construct(moodle_page $page, $target) { | |
50 | $this->strings = new stdClass; | |
51 | parent::__construct($page, $target); | |
52 | } | |
53 | ||
cb76fec0 PS |
54 | /** |
55 | * Renders course info box. | |
56 | * | |
57 | * @param stdClass $course | |
58 | * @return string | |
59 | */ | |
60 | public function course_info_box(stdClass $course) { | |
61 | global $CFG; | |
62 | ||
63 | $context = context_course::instance($course->id); | |
64 | ||
65 | $content = ''; | |
66 | $content .= $this->output->box_start('generalbox info'); | |
67 | ||
68 | $summary = file_rewrite_pluginfile_urls($course->summary, 'pluginfile.php', $context->id, 'course', 'summary', null); | |
69 | $content .= format_text($summary, $course->summaryformat, array('overflowdiv'=>true), $course->id); | |
70 | if (!empty($CFG->coursecontact)) { | |
71 | $coursecontactroles = explode(',', $CFG->coursecontact); | |
72 | foreach ($coursecontactroles as $roleid) { | |
73 | if ($users = get_role_users($roleid, $context, true)) { | |
74 | foreach ($users as $teacher) { | |
75 | $role = new stdClass(); | |
76 | $role->id = $teacher->roleid; | |
77 | $role->name = $teacher->rolename; | |
78 | $role->shortname = $teacher->roleshortname; | |
79 | $role->coursealias = $teacher->rolecoursealias; | |
80 | $fullname = fullname($teacher, has_capability('moodle/site:viewfullnames', $context)); | |
81 | $namesarray[] = role_get_name($role, $context).': <a href="'.$CFG->wwwroot.'/user/view.php?id='. | |
82 | $teacher->id.'&course='.SITEID.'">'.$fullname.'</a>'; | |
83 | } | |
84 | } | |
85 | } | |
86 | ||
87 | if (!empty($namesarray)) { | |
88 | $content .= "<ul class=\"teachers\">\n<li>"; | |
89 | $content .= implode('</li><li>', $namesarray); | |
90 | $content .= "</li></ul>"; | |
91 | } | |
92 | } | |
93 | ||
94 | $content .= $this->output->box_end(); | |
95 | ||
96 | return $content; | |
97 | } | |
98 | ||
24e27ac0 SH |
99 | /** |
100 | * Renderers a structured array of courses and categories into a nice | |
101 | * XHTML tree structure. | |
102 | * | |
103 | * This method was designed initially to display the front page course/category | |
104 | * combo view. The structure can be retrieved by get_course_category_tree() | |
105 | * | |
106 | * @param array $structure | |
107 | * @return string | |
108 | */ | |
109 | public function course_category_tree(array $structure) { | |
24e27ac0 SH |
110 | $this->strings->summary = get_string('summary'); |
111 | ||
112 | // Generate an id and the required JS call to make this a nice widget | |
113 | $id = html_writer::random_id('course_category_tree'); | |
c8ffba95 | 114 | $this->page->requires->js_init_call('M.util.init_toggle_class_on_click', array($id, '.category.with_children .category_label', 'collapsed', '.category.with_children')); |
24e27ac0 SH |
115 | |
116 | // Start content generation | |
117 | $content = html_writer::start_tag('div', array('class'=>'course_category_tree', 'id'=>$id)); | |
118 | foreach ($structure as $category) { | |
119 | $content .= $this->course_category_tree_category($category); | |
120 | } | |
121 | $content .= html_writer::start_tag('div', array('class'=>'controls')); | |
122 | $content .= html_writer::tag('div', get_string('collapseall'), array('class'=>'addtoall expandall')); | |
123 | $content .= html_writer::tag('div', get_string('expandall'), array('class'=>'removefromall collapseall')); | |
124 | $content .= html_writer::end_tag('div'); | |
125 | $content .= html_writer::end_tag('div'); | |
df997f84 | 126 | |
24e27ac0 SH |
127 | // Return the course category tree HTML |
128 | return $content; | |
129 | } | |
130 | ||
131 | /** | |
132 | * Renderers a category for use with course_category_tree | |
133 | * | |
134 | * @param array $category | |
135 | * @param int $depth | |
136 | * @return string | |
137 | */ | |
138 | protected function course_category_tree_category(stdClass $category, $depth=1) { | |
139 | $content = ''; | |
3754f4f3 ARN |
140 | $hassubcategories = (isset($category->categories) && count($category->categories)>0); |
141 | $hascourses = (isset($category->courses) && count($category->courses)>0); | |
24e27ac0 SH |
142 | $classes = array('category'); |
143 | if ($category->parent != 0) { | |
144 | $classes[] = 'subcategory'; | |
145 | } | |
d703f226 SH |
146 | if (empty($category->visible)) { |
147 | $classes[] = 'dimmed_category'; | |
148 | } | |
24e27ac0 SH |
149 | if ($hassubcategories || $hascourses) { |
150 | $classes[] = 'with_children'; | |
151 | if ($depth > 1) { | |
152 | $classes[] = 'collapsed'; | |
153 | } | |
154 | } | |
9a5e297b | 155 | $categoryname = format_string($category->name, true, array('context' => context_coursecat::instance($category->id))); |
63390481 | 156 | |
24e27ac0 SH |
157 | $content .= html_writer::start_tag('div', array('class'=>join(' ', $classes))); |
158 | $content .= html_writer::start_tag('div', array('class'=>'category_label')); | |
63390481 | 159 | $content .= html_writer::link(new moodle_url('/course/category.php', array('id'=>$category->id)), $categoryname, array('class'=>'category_link')); |
24e27ac0 SH |
160 | $content .= html_writer::end_tag('div'); |
161 | if ($hassubcategories) { | |
162 | $content .= html_writer::start_tag('div', array('class'=>'subcategories')); | |
163 | foreach ($category->categories as $subcategory) { | |
164 | $content .= $this->course_category_tree_category($subcategory, $depth+1); | |
165 | } | |
166 | $content .= html_writer::end_tag('div'); | |
167 | } | |
168 | if ($hascourses) { | |
169 | $content .= html_writer::start_tag('div', array('class'=>'courses')); | |
170 | $coursecount = 0; | |
6a1273cb | 171 | $strinfo = new lang_string('info'); |
24e27ac0 SH |
172 | foreach ($category->courses as $course) { |
173 | $classes = array('course'); | |
d2fd38be PS |
174 | $linkclass = 'course_link'; |
175 | if (!$course->visible) { | |
176 | $linkclass .= ' dimmed'; | |
177 | } | |
24e27ac0 SH |
178 | $coursecount ++; |
179 | $classes[] = ($coursecount%2)?'odd':'even'; | |
180 | $content .= html_writer::start_tag('div', array('class'=>join(' ', $classes))); | |
f4c23f03 | 181 | $content .= html_writer::link(new moodle_url('/course/view.php', array('id'=>$course->id)), format_string($course->fullname), array('class'=>$linkclass)); |
24e27ac0 SH |
182 | $content .= html_writer::start_tag('div', array('class'=>'course_info clearfix')); |
183 | ||
bf423bb1 PS |
184 | // print enrol info |
185 | if ($icons = enrol_get_course_info_icons($course)) { | |
186 | foreach ($icons as $pix_icon) { | |
187 | $content .= $this->render($pix_icon); | |
188 | } | |
189 | } | |
190 | ||
24e27ac0 | 191 | if ($course->summary) { |
6a1273cb | 192 | $url = new moodle_url('/course/info.php', array('id' => $course->id)); |
24e27ac0 | 193 | $image = html_writer::empty_tag('img', array('src'=>$this->output->pix_url('i/info'), 'alt'=>$this->strings->summary)); |
6a1273cb | 194 | $content .= $this->action_link($url, $image, new popup_action('click', $url, 'courseinfo'), array('title' => $this->strings->summary)); |
24e27ac0 SH |
195 | } |
196 | $content .= html_writer::end_tag('div'); | |
197 | $content .= html_writer::end_tag('div'); | |
198 | } | |
199 | $content .= html_writer::end_tag('div'); | |
200 | } | |
201 | $content .= html_writer::end_tag('div'); | |
202 | return $content; | |
203 | } | |
01e0e704 ARN |
204 | |
205 | /** | |
206 | * Build the HTML for the module chooser javascript popup | |
207 | * | |
208 | * @param array $modules A set of modules as returned form @see | |
209 | * get_module_metadata | |
210 | * @param object $course The course that will be displayed | |
211 | * @return string The composed HTML for the module | |
212 | */ | |
213 | public function course_modchooser($modules, $course) { | |
697ff999 MG |
214 | static $isdisplayed = false; |
215 | if ($isdisplayed) { | |
216 | return ''; | |
217 | } | |
218 | $isdisplayed = true; | |
219 | ||
220 | // Add the module chooser | |
221 | $this->page->requires->yui_module('moodle-course-modchooser', | |
222 | 'M.course.init_chooser', | |
223 | array(array('courseid' => $course->id, 'closeButtonTitle' => get_string('close', 'editor'))) | |
224 | ); | |
225 | $this->page->requires->strings_for_js(array( | |
226 | 'addresourceoractivity', | |
227 | 'modchooserenable', | |
228 | 'modchooserdisable', | |
229 | ), 'moodle'); | |
01e0e704 ARN |
230 | |
231 | // Add the header | |
1edff8c7 | 232 | $header = html_writer::tag('div', get_string('addresourceoractivity', 'moodle'), |
255dd8d1 | 233 | array('class' => 'hd choosertitle')); |
01e0e704 ARN |
234 | |
235 | $formcontent = html_writer::start_tag('form', array('action' => new moodle_url('/course/jumpto.php'), | |
236 | 'id' => 'chooserform', 'method' => 'post')); | |
237 | $formcontent .= html_writer::start_tag('div', array('id' => 'typeformdiv')); | |
238 | $formcontent .= html_writer::tag('input', '', array('type' => 'hidden', 'id' => 'course', | |
239 | 'name' => 'course', 'value' => $course->id)); | |
240 | $formcontent .= html_writer::tag('input', '', | |
0a2fb910 | 241 | array('type' => 'hidden', 'class' => 'jump', 'name' => 'jump', 'value' => '')); |
01e0e704 ARN |
242 | $formcontent .= html_writer::tag('input', '', array('type' => 'hidden', 'name' => 'sesskey', |
243 | 'value' => sesskey())); | |
244 | $formcontent .= html_writer::end_tag('div'); | |
245 | ||
246 | // Put everything into one tag 'options' | |
247 | $formcontent .= html_writer::start_tag('div', array('class' => 'options')); | |
248 | $formcontent .= html_writer::tag('div', get_string('selectmoduletoviewhelp', 'moodle'), | |
249 | array('class' => 'instruction')); | |
250 | // Put all options into one tag 'alloptions' to allow us to handle scrolling | |
251 | $formcontent .= html_writer::start_tag('div', array('class' => 'alloptions')); | |
252 | ||
5035ed63 MA |
253 | // Activities |
254 | $activities = array_filter($modules, function($mod) { | |
255 | return ($mod->archetype !== MOD_ARCHETYPE_RESOURCE && $mod->archetype !== MOD_ARCHETYPE_SYSTEM); | |
256 | }); | |
01e0e704 ARN |
257 | if (count($activities)) { |
258 | $formcontent .= $this->course_modchooser_title('activities'); | |
259 | $formcontent .= $this->course_modchooser_module_types($activities); | |
260 | } | |
261 | ||
463ccee1 | 262 | // Resources |
5035ed63 MA |
263 | $resources = array_filter($modules, function($mod) { |
264 | return ($mod->archetype === MOD_ARCHETYPE_RESOURCE); | |
265 | }); | |
48a5e55e ARN |
266 | if (count($resources)) { |
267 | $formcontent .= $this->course_modchooser_title('resources'); | |
268 | $formcontent .= $this->course_modchooser_module_types($resources); | |
269 | } | |
270 | ||
01e0e704 ARN |
271 | $formcontent .= html_writer::end_tag('div'); // modoptions |
272 | $formcontent .= html_writer::end_tag('div'); // types | |
273 | ||
274 | $formcontent .= html_writer::start_tag('div', array('class' => 'submitbuttons')); | |
af75421c | 275 | $formcontent .= html_writer::tag('input', '', |
0a2fb910 | 276 | array('type' => 'submit', 'name' => 'submitbutton', 'class' => 'submitbutton', 'value' => get_string('add'))); |
8ff6c5ee | 277 | $formcontent .= html_writer::tag('input', '', |
0a2fb910 | 278 | array('type' => 'submit', 'name' => 'addcancel', 'class' => 'addcancel', 'value' => get_string('cancel'))); |
01e0e704 ARN |
279 | $formcontent .= html_writer::end_tag('div'); |
280 | $formcontent .= html_writer::end_tag('form'); | |
281 | ||
282 | // Wrap the whole form in a div | |
283 | $formcontent = html_writer::tag('div', $formcontent, array('id' => 'chooseform')); | |
284 | ||
285 | // Put all of the content together | |
286 | $content = $formcontent; | |
287 | ||
255dd8d1 ARN |
288 | $content = html_writer::tag('div', $content, array('class' => 'choosercontainer')); |
289 | return $header . html_writer::tag('div', $content, array('class' => 'chooserdialoguebody')); | |
01e0e704 ARN |
290 | } |
291 | ||
292 | /** | |
293 | * Build the HTML for a specified set of modules | |
294 | * | |
295 | * @param array $modules A set of modules as used by the | |
296 | * course_modchooser_module function | |
297 | * @return string The composed HTML for the module | |
298 | */ | |
299 | protected function course_modchooser_module_types($modules) { | |
300 | $return = ''; | |
301 | foreach ($modules as $module) { | |
302 | if (!isset($module->types)) { | |
303 | $return .= $this->course_modchooser_module($module); | |
304 | } else { | |
305 | $return .= $this->course_modchooser_module($module, array('nonoption')); | |
306 | foreach ($module->types as $type) { | |
307 | $return .= $this->course_modchooser_module($type, array('option', 'subtype')); | |
308 | } | |
309 | } | |
310 | } | |
311 | return $return; | |
312 | } | |
313 | ||
314 | /** | |
315 | * Return the HTML for the specified module adding any required classes | |
316 | * | |
317 | * @param object $module An object containing the title, and link. An | |
318 | * icon, and help text may optionally be specified. If the module | |
319 | * contains subtypes in the types option, then these will also be | |
320 | * displayed. | |
321 | * @param array $classes Additional classes to add to the encompassing | |
322 | * div element | |
323 | * @return string The composed HTML for the module | |
324 | */ | |
325 | protected function course_modchooser_module($module, $classes = array('option')) { | |
326 | $output = ''; | |
327 | $output .= html_writer::start_tag('div', array('class' => implode(' ', $classes))); | |
328 | $output .= html_writer::start_tag('label', array('for' => 'module_' . $module->name)); | |
329 | if (!isset($module->types)) { | |
330 | $output .= html_writer::tag('input', '', array('type' => 'radio', | |
331 | 'name' => 'jumplink', 'id' => 'module_' . $module->name, 'value' => $module->link)); | |
332 | } | |
333 | ||
334 | $output .= html_writer::start_tag('span', array('class' => 'modicon')); | |
335 | if (isset($module->icon)) { | |
336 | // Add an icon if we have one | |
337 | $output .= $module->icon; | |
338 | } | |
339 | $output .= html_writer::end_tag('span'); | |
340 | ||
341 | $output .= html_writer::tag('span', $module->title, array('class' => 'typename')); | |
342 | if (!isset($module->help)) { | |
343 | // Add help if found | |
344 | $module->help = get_string('nohelpforactivityorresource', 'moodle'); | |
345 | } | |
346 | ||
347 | // Format the help text using markdown with the following options | |
348 | $options = new stdClass(); | |
349 | $options->trusted = false; | |
350 | $options->noclean = false; | |
351 | $options->smiley = false; | |
352 | $options->filter = false; | |
353 | $options->para = true; | |
354 | $options->newlines = false; | |
355 | $options->overflowdiv = false; | |
356 | $module->help = format_text($module->help, FORMAT_MARKDOWN, $options); | |
357 | $output .= html_writer::tag('span', $module->help, array('class' => 'typesummary')); | |
358 | $output .= html_writer::end_tag('label'); | |
359 | $output .= html_writer::end_tag('div'); | |
360 | ||
361 | return $output; | |
362 | } | |
363 | ||
364 | protected function course_modchooser_title($title, $identifier = null) { | |
365 | $module = new stdClass(); | |
366 | $module->name = $title; | |
367 | $module->types = array(); | |
368 | $module->title = get_string($title, $identifier); | |
369 | $module->help = ''; | |
370 | return $this->course_modchooser_module($module, array('moduletypetitle')); | |
371 | } | |
f558b291 MG |
372 | |
373 | /** | |
374 | * Renders HTML for displaying the sequence of course module editing buttons | |
375 | * | |
376 | * @see course_get_cm_edit_actions() | |
377 | * | |
378 | * @param array $actions array of action_link or pix_icon objects | |
379 | * @return string | |
380 | */ | |
381 | public function course_section_cm_edit_actions($actions) { | |
382 | $output = html_writer::start_tag('span', array('class' => 'commands')); | |
383 | foreach ($actions as $action) { | |
384 | if ($action instanceof renderable) { | |
385 | $output .= $this->output->render($action); | |
386 | } else { | |
387 | $output .= $action; | |
388 | } | |
389 | } | |
390 | $output .= html_writer::end_tag('span'); | |
391 | return $output; | |
392 | } | |
9a6aa5c1 MG |
393 | |
394 | /** | |
395 | * Renders HTML for the menus to add activities and resources to the current course | |
396 | * | |
397 | * @param stdClass $course | |
398 | * @param int $section relative section number (field course_sections.section) | |
399 | * @param int $sectionreturn The section to link back to | |
400 | * @param array $displayoptions additional display options, for example blocks add | |
401 | * option 'inblock' => true, suggesting to display controls vertically | |
402 | * @return string | |
403 | */ | |
404 | function course_section_add_cm_control($course, $section, $sectionreturn = null, $displayoptions = array()) { | |
405 | global $CFG; | |
406 | ||
407 | $vertical = !empty($displayoptions['inblock']); | |
408 | ||
409 | // check to see if user can add menus and there are modules to add | |
410 | if (!has_capability('moodle/course:manageactivities', context_course::instance($course->id)) | |
411 | || !$this->page->user_is_editing() | |
412 | || !($modnames = get_module_types_names()) || empty($modnames)) { | |
413 | return ''; | |
414 | } | |
415 | ||
416 | // Retrieve all modules with associated metadata | |
417 | $modules = get_module_metadata($course, $modnames, $sectionreturn); | |
418 | $urlparams = array('section' => $section); | |
419 | ||
420 | // We'll sort resources and activities into two lists | |
421 | $activities = array(MOD_CLASS_ACTIVITY => array(), MOD_CLASS_RESOURCE => array()); | |
422 | ||
423 | foreach ($modules as $module) { | |
424 | if (!array_key_exists($module->archetype, $activities)) { | |
425 | // System modules cannot be added by user, do not add to dropdown | |
426 | } else if (isset($module->types)) { | |
427 | // This module has a subtype | |
428 | // NOTE: this is legacy stuff, module subtypes are very strongly discouraged!! | |
429 | $subtypes = array(); | |
430 | foreach ($module->types as $subtype) { | |
431 | $link = $subtype->link->out(true, $urlparams); | |
432 | $subtypes[$link] = $subtype->title; | |
433 | } | |
434 | ||
435 | // Sort module subtypes into the list | |
436 | if (!empty($module->title)) { | |
437 | // This grouping has a name | |
438 | $activities[$module->archetype][] = array($module->title => $subtypes); | |
439 | } else { | |
440 | // This grouping does not have a name | |
441 | $activities[$module->archetype] = array_merge($activities[$module->archetype], $subtypes); | |
442 | } | |
443 | } else { | |
444 | // This module has no subtypes | |
445 | $link = $module->link->out(true, $urlparams); | |
446 | $activities[$module->archetype][$link] = $module->title; | |
447 | } | |
448 | } | |
449 | ||
450 | $straddactivity = get_string('addactivity'); | |
451 | $straddresource = get_string('addresource'); | |
452 | $sectionname = get_section_name($course, $section); | |
453 | $strresourcelabel = get_string('addresourcetosection', null, $sectionname); | |
454 | $stractivitylabel = get_string('addactivitytosection', null, $sectionname); | |
455 | ||
456 | $output = html_writer::start_tag('div', array('class' => 'section_add_menus', 'id' => 'add_menus-section-' . $section)); | |
457 | ||
458 | if (!$vertical) { | |
459 | $output .= html_writer::start_tag('div', array('class' => 'horizontal')); | |
460 | } | |
461 | ||
462 | if (!empty($activities[MOD_CLASS_RESOURCE])) { | |
463 | $select = new url_select($activities[MOD_CLASS_RESOURCE], '', array(''=>$straddresource), "ressection$section"); | |
464 | $select->set_help_icon('resources'); | |
465 | $select->set_label($strresourcelabel, array('class' => 'accesshide')); | |
466 | $output .= $this->output->render($select); | |
467 | } | |
468 | ||
469 | if (!empty($activities[MOD_CLASS_ACTIVITY])) { | |
470 | $select = new url_select($activities[MOD_CLASS_ACTIVITY], '', array(''=>$straddactivity), "section$section"); | |
471 | $select->set_help_icon('activities'); | |
472 | $select->set_label($stractivitylabel, array('class' => 'accesshide')); | |
473 | $output .= $this->output->render($select); | |
474 | } | |
475 | ||
476 | if (!$vertical) { | |
477 | $output .= html_writer::end_tag('div'); | |
478 | } | |
479 | ||
480 | $output .= html_writer::end_tag('div'); | |
481 | ||
482 | if (course_ajax_enabled($course) && $course->id == $this->page->course->id) { | |
483 | // modchooser can be added only for the current course set on the page! | |
484 | $straddeither = get_string('addresourceoractivity'); | |
485 | // The module chooser link | |
486 | $modchooser = html_writer::start_tag('div', array('class' => 'mdl-right')); | |
487 | $modchooser.= html_writer::start_tag('div', array('class' => 'section-modchooser')); | |
488 | $icon = $this->output->pix_icon('t/add', ''); | |
489 | $span = html_writer::tag('span', $straddeither, array('class' => 'section-modchooser-text')); | |
490 | $modchooser .= html_writer::tag('span', $icon . $span, array('class' => 'section-modchooser-link')); | |
491 | $modchooser.= html_writer::end_tag('div'); | |
492 | $modchooser.= html_writer::end_tag('div'); | |
493 | ||
494 | // Wrap the normal output in a noscript div | |
495 | $usemodchooser = get_user_preferences('usemodchooser', $CFG->modchooserdefault); | |
496 | if ($usemodchooser) { | |
497 | $output = html_writer::tag('div', $output, array('class' => 'hiddenifjs addresourcedropdown')); | |
498 | $modchooser = html_writer::tag('div', $modchooser, array('class' => 'visibleifjs addresourcemodchooser')); | |
499 | } else { | |
500 | // If the module chooser is disabled, we need to ensure that the dropdowns are shown even if javascript is disabled | |
501 | $output = html_writer::tag('div', $output, array('class' => 'show addresourcedropdown')); | |
502 | $modchooser = html_writer::tag('div', $modchooser, array('class' => 'hide addresourcemodchooser')); | |
503 | } | |
504 | $output = $this->course_modchooser($modules, $course) . $modchooser . $output; | |
505 | } | |
506 | ||
507 | return $output; | |
508 | } | |
7e29340f MG |
509 | |
510 | /** | |
511 | * Renders html for completion box on course page | |
512 | * | |
513 | * If completion is disabled, returns empty string | |
514 | * If completion is automatic, returns an icon of the current completion state | |
515 | * If completion is manual, returns a form (with an icon inside) that allows user to | |
516 | * toggle completion | |
517 | * | |
518 | * @param stdClass $course course object | |
519 | * @param completion_info $completioninfo completion info for the course, it is recommended | |
520 | * to fetch once for all modules in course/section for performance | |
521 | * @param cm_info $mod module to show completion for | |
522 | * @param array $displayoptions display options, not used in core | |
523 | * @return string | |
524 | */ | |
525 | public function course_section_cm_completion($course, &$completioninfo, cm_info $mod, $displayoptions = array()) { | |
526 | global $CFG; | |
527 | $output = ''; | |
528 | if (!empty($displayoptions['hidecompletion']) || !isloggedin() || isguestuser() || !$mod->uservisible) { | |
529 | return $output; | |
530 | } | |
531 | if ($completioninfo === null) { | |
532 | $completioninfo = new completion_info($course); | |
533 | } | |
534 | $completion = $completioninfo->is_enabled($mod); | |
535 | if ($completion == COMPLETION_TRACKING_NONE) { | |
536 | return $output; | |
537 | } | |
538 | ||
539 | $completiondata = $completioninfo->get_data($mod, true); | |
540 | $completionicon = ''; | |
541 | ||
542 | if ($this->page->user_is_editing()) { | |
543 | switch ($completion) { | |
544 | case COMPLETION_TRACKING_MANUAL : | |
545 | $completionicon = 'manual-enabled'; break; | |
546 | case COMPLETION_TRACKING_AUTOMATIC : | |
547 | $completionicon = 'auto-enabled'; break; | |
548 | } | |
549 | } else if ($completion == COMPLETION_TRACKING_MANUAL) { | |
550 | switch($completiondata->completionstate) { | |
551 | case COMPLETION_INCOMPLETE: | |
552 | $completionicon = 'manual-n'; break; | |
553 | case COMPLETION_COMPLETE: | |
554 | $completionicon = 'manual-y'; break; | |
555 | } | |
556 | } else { // Automatic | |
557 | switch($completiondata->completionstate) { | |
558 | case COMPLETION_INCOMPLETE: | |
559 | $completionicon = 'auto-n'; break; | |
560 | case COMPLETION_COMPLETE: | |
561 | $completionicon = 'auto-y'; break; | |
562 | case COMPLETION_COMPLETE_PASS: | |
563 | $completionicon = 'auto-pass'; break; | |
564 | case COMPLETION_COMPLETE_FAIL: | |
565 | $completionicon = 'auto-fail'; break; | |
566 | } | |
567 | } | |
568 | if ($completionicon) { | |
569 | $formattedname = $mod->get_formatted_name(); | |
570 | $imgalt = get_string('completion-alt-' . $completionicon, 'completion', $formattedname); | |
571 | if ($completion == COMPLETION_TRACKING_MANUAL && !$this->page->user_is_editing()) { | |
572 | $imgtitle = get_string('completion-title-' . $completionicon, 'completion', $formattedname); | |
573 | $newstate = | |
574 | $completiondata->completionstate == COMPLETION_COMPLETE | |
575 | ? COMPLETION_INCOMPLETE | |
576 | : COMPLETION_COMPLETE; | |
577 | // In manual mode the icon is a toggle form... | |
578 | ||
579 | // If this completion state is used by the | |
580 | // conditional activities system, we need to turn | |
581 | // off the JS. | |
582 | $extraclass = ''; | |
583 | if (!empty($CFG->enableavailability) && | |
584 | condition_info::completion_value_used_as_condition($course, $mod)) { | |
585 | $extraclass = ' preventjs'; | |
586 | } | |
587 | $output .= html_writer::start_tag('form', array('method' => 'post', | |
588 | 'action' => new moodle_url('/course/togglecompletion.php'), | |
589 | 'class' => 'togglecompletion'. $extraclass)); | |
590 | $output .= html_writer::start_tag('div'); | |
591 | $output .= html_writer::empty_tag('input', array( | |
592 | 'type' => 'hidden', 'name' => 'id', 'value' => $mod->id)); | |
593 | $output .= html_writer::empty_tag('input', array( | |
594 | 'type' => 'hidden', 'name' => 'sesskey', 'value' => sesskey())); | |
595 | $output .= html_writer::empty_tag('input', array( | |
596 | 'type' => 'hidden', 'name' => 'modulename', 'value' => $mod->name)); | |
597 | $output .= html_writer::empty_tag('input', array( | |
598 | 'type' => 'hidden', 'name' => 'completionstate', 'value' => $newstate)); | |
599 | $output .= html_writer::empty_tag('input', array( | |
600 | 'type' => 'image', | |
601 | 'src' => $this->output->pix_url('i/completion-'.$completionicon), | |
602 | 'alt' => $imgalt, 'title' => $imgtitle)); | |
603 | $output .= html_writer::end_tag('div'); | |
604 | $output .= html_writer::end_tag('form'); | |
605 | } else { | |
606 | // In auto mode, or when editing, the icon is just an image | |
607 | $completionpixicon = new pix_icon('i/completion-'.$completionicon, $imgalt, '', | |
608 | array('title' => $imgalt)); | |
609 | $output .= html_writer::tag('span', $this->output->render($completionpixicon), | |
610 | array('class' => 'autocompletion')); | |
611 | } | |
612 | } | |
613 | return $output; | |
614 | } | |
ed513fad MG |
615 | |
616 | /** | |
617 | * Checks if course module has any conditions that may make it unavailable for | |
618 | * all or some of the students | |
619 | * | |
620 | * This function is internal and is only used to create CSS classes for the module name/text | |
621 | * | |
622 | * @param cm_info $mod | |
623 | * @return bool | |
624 | */ | |
625 | protected function is_cm_conditionally_hidden(cm_info $mod) { | |
626 | global $CFG; | |
627 | $conditionalhidden = false; | |
628 | if (!empty($CFG->enableavailability)) { | |
629 | $conditionalhidden = $mod->availablefrom > time() || | |
630 | ($mod->availableuntil && $mod->availableuntil < time()) || | |
631 | count($mod->conditionsgrade) > 0 || | |
632 | count($mod->conditionscompletion) > 0; | |
633 | } | |
634 | return $conditionalhidden; | |
635 | } | |
636 | ||
637 | /** | |
638 | * Renders html to display a name with the link to the course module on a course page | |
639 | * | |
640 | * If module is unavailable for user but still needs to be displayed | |
641 | * in the list, just the name is returned without a link | |
642 | * | |
643 | * Note, that for course modules that never have separate pages (i.e. labels) | |
644 | * this function return an empty string | |
645 | * | |
646 | * @param cm_info $mod | |
647 | * @param array $displayoptions | |
648 | * @return string | |
649 | */ | |
650 | public function course_section_cm_name(cm_info $mod, $displayoptions = array()) { | |
651 | global $CFG; | |
652 | $output = ''; | |
653 | if (!$mod->uservisible && | |
654 | (empty($mod->showavailability) || empty($mod->availableinfo))) { | |
655 | // nothing to be displayed to the user | |
656 | return $output; | |
657 | } | |
658 | $url = $mod->get_url(); | |
659 | if (!$url) { | |
660 | return $output; | |
661 | } | |
662 | ||
663 | //Accessibility: for files get description via icon, this is very ugly hack! | |
664 | $instancename = $mod->get_formatted_name(); | |
665 | $altname = ''; | |
666 | $altname = $mod->modfullname; | |
667 | // Avoid unnecessary duplication: if e.g. a forum name already | |
668 | // includes the word forum (or Forum, etc) then it is unhelpful | |
669 | // to include that in the accessible description that is added. | |
670 | if (false !== strpos(textlib::strtolower($instancename), | |
671 | textlib::strtolower($altname))) { | |
672 | $altname = ''; | |
673 | } | |
674 | // File type after name, for alphabetic lists (screen reader). | |
675 | if ($altname) { | |
676 | $altname = get_accesshide(' '.$altname); | |
677 | } | |
678 | ||
679 | $conditionalhidden = $this->is_cm_conditionally_hidden($mod); | |
680 | $accessiblebutdim = !$mod->visible || $conditionalhidden; | |
681 | ||
682 | $linkclasses = ''; | |
683 | $accesstext = ''; | |
684 | $textclasses = ''; | |
685 | if ($accessiblebutdim) { | |
686 | $linkclasses .= ' dimmed'; | |
687 | $textclasses .= ' dimmed_text'; | |
688 | if ($conditionalhidden) { | |
689 | $linkclasses .= ' conditionalhidden'; | |
690 | $textclasses .= ' conditionalhidden'; | |
691 | } | |
692 | if ($mod->uservisible) { | |
693 | // show accessibility note only if user can access the module himself | |
694 | $accesstext = get_accesshide(get_string('hiddenfromstudents').': '); | |
695 | } | |
696 | } | |
697 | ||
698 | // Get on-click attribute value if specified and decode the onclick - it | |
699 | // has already been encoded for display (puke). | |
700 | $onclick = htmlspecialchars_decode($mod->get_on_click(), ENT_QUOTES); | |
701 | ||
702 | $groupinglabel = ''; | |
703 | if (!empty($mod->groupingid) && has_capability('moodle/course:managegroups', context_course::instance($mod->course))) { | |
704 | $groupings = groups_get_all_groupings($mod->course); | |
705 | $groupinglabel = html_writer::tag('span', '('.format_string($groupings[$mod->groupingid]->name).')', | |
706 | array('class' => 'groupinglabel '.$textclasses)); | |
707 | } | |
708 | ||
709 | // Display link itself. | |
710 | $activitylink = html_writer::empty_tag('img', array('src' => $mod->get_icon_url(), | |
711 | 'class' => 'iconlarge activityicon', 'alt' => $mod->modfullname)) . $accesstext . | |
712 | html_writer::tag('span', $instancename . $altname, array('class' => 'instancename')); | |
713 | if ($mod->uservisible) { | |
714 | $output .= html_writer::link($url, $activitylink, array('class' => $linkclasses, 'onclick' => $onclick)) . | |
715 | $groupinglabel; | |
716 | } else { | |
717 | // We may be displaying this just in order to show information | |
718 | // about visibility, without the actual link ($mod->uservisible) | |
719 | $output .= html_writer::tag('div', $activitylink, array('class' => $textclasses)) . | |
720 | $groupinglabel; | |
721 | } | |
722 | return $output; | |
723 | } | |
724 | ||
725 | /** | |
726 | * Renders html to display the module content on the course page (i.e. text of the labels) | |
727 | * | |
728 | * @param cm_info $mod | |
729 | * @param array $displayoptions | |
730 | * @return string | |
731 | */ | |
732 | public function course_section_cm_text(cm_info $mod, $displayoptions = array()) { | |
733 | $output = ''; | |
734 | if (!$mod->uservisible && | |
735 | (empty($mod->showavailability) || empty($mod->availableinfo))) { | |
736 | // nothing to be displayed to the user | |
737 | return $output; | |
738 | } | |
739 | $content = $mod->get_formatted_content(array('overflowdiv' => true, 'noclean' => true)); | |
740 | $conditionalhidden = $this->is_cm_conditionally_hidden($mod); | |
741 | $accessiblebutdim = !$mod->visible || $conditionalhidden; | |
742 | $textclasses = ''; | |
743 | $accesstext = ''; | |
744 | if ($accessiblebutdim) { | |
745 | $textclasses .= ' dimmed_text'; | |
746 | if ($conditionalhidden) { | |
747 | $textclasses .= ' conditionalhidden'; | |
748 | } | |
749 | if ($mod->uservisible) { | |
750 | // show accessibility note only if user can access the module himself | |
751 | $accesstext = get_accesshide(get_string('hiddenfromstudents').': '); | |
752 | } | |
753 | } | |
754 | if ($mod->get_url()) { | |
755 | if ($content) { | |
756 | // If specified, display extra content after link. | |
757 | $output = html_writer::tag('div', $content, array('class' => | |
758 | trim('contentafterlink ' . $textclasses))); | |
759 | } | |
760 | } else { | |
761 | // No link, so display only content. | |
762 | $output = html_writer::tag('div', $accesstext . $content, array('class' => $textclasses)); | |
763 | } | |
764 | return $output; | |
765 | } | |
766 | ||
767 | /** | |
768 | * Renders HTML to show course module availability information (for someone who isn't allowed | |
769 | * to see the activity itself, or for staff) | |
770 | * | |
771 | * @param cm_info $mod | |
772 | * @param array $displayoptions | |
773 | * @return string | |
774 | */ | |
775 | public function course_section_cm_availability(cm_info $mod, $displayoptions = array()) { | |
776 | global $CFG; | |
777 | if (!$mod->uservisible) { | |
778 | // this is a student who is not allowed to see the module but might be allowed | |
779 | // to see availability info (i.e. "Available from ...") | |
780 | if (!empty($mod->showavailability) && !empty($mod->availableinfo)) { | |
781 | $output = html_writer::tag('div', $mod->availableinfo, array('class' => 'availabilityinfo')); | |
782 | } | |
783 | return $output; | |
784 | } | |
785 | // this is a teacher who is allowed to see module but still should see the | |
786 | // information that module is not available to all/some students | |
787 | $modcontext = context_module::instance($mod->id); | |
788 | $canviewhidden = has_capability('moodle/course:viewhiddenactivities', $modcontext); | |
789 | if ($canviewhidden && !empty($CFG->enableavailability)) { | |
790 | // Don't add availability information if user is not editing and activity is hidden. | |
791 | if ($mod->visible || $this->page->user_is_editing()) { | |
792 | $hidinfoclass = ''; | |
793 | if (!$mod->visible) { | |
794 | $hidinfoclass = 'hide'; | |
795 | } | |
796 | $ci = new condition_info($mod); | |
797 | $fullinfo = $ci->get_full_information(); | |
798 | if($fullinfo) { | |
799 | echo '<div class="availabilityinfo '.$hidinfoclass.'">'.get_string($mod->showavailability | |
800 | ? 'userrestriction_visible' | |
801 | : 'userrestriction_hidden','condition', | |
802 | $fullinfo).'</div>'; | |
803 | } | |
804 | } | |
805 | } | |
806 | return ''; | |
807 | } | |
f4c23f03 | 808 | } |