Merge branch 'MDL-53281-master' of git://github.com/merrill-oakland/moodle
[moodle.git] / course / format / renderer.php
blobc88d14d947b310cc7b4847a8c30b9aaeabf9dfa8
1 <?php
2 // This file is part of Moodle - http://moodle.org/
3 //
4 // Moodle is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // Moodle is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
14 // You should have received a copy of the GNU General Public License
15 // along with Moodle. If not, see <http://www.gnu.org/licenses/>.
17 /**
18 * Base renderer for outputting course formats.
20 * @package core
21 * @copyright 2012 Dan Poltawski
22 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
23 * @since Moodle 2.3
26 defined('MOODLE_INTERNAL') || die();
29 /**
30 * This is a convenience renderer which can be used by section based formats
31 * to reduce code duplication. It is not necessary for all course formats to
32 * use this and its likely to change in future releases.
34 * @package core
35 * @copyright 2012 Dan Poltawski
36 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
37 * @since Moodle 2.3
39 abstract class format_section_renderer_base extends plugin_renderer_base {
41 /** @var contains instance of core course renderer */
42 protected $courserenderer;
44 /**
45 * Constructor method, calls the parent constructor
47 * @param moodle_page $page
48 * @param string $target one of rendering target constants
50 public function __construct(moodle_page $page, $target) {
51 parent::__construct($page, $target);
52 $this->courserenderer = $this->page->get_renderer('core', 'course');
55 /**
56 * Generate the starting container html for a list of sections
57 * @return string HTML to output.
59 abstract protected function start_section_list();
61 /**
62 * Generate the closing container html for a list of sections
63 * @return string HTML to output.
65 abstract protected function end_section_list();
67 /**
68 * Generate the title for this section page
69 * @return string the page title
71 abstract protected function page_title();
73 /**
74 * Generate the section title, wraps it in a link to the section page if page is to be displayed on a separate page
76 * @param stdClass $section The course_section entry from DB
77 * @param stdClass $course The course entry from DB
78 * @return string HTML to output.
80 public function section_title($section, $course) {
81 $title = get_section_name($course, $section);
82 $url = course_get_url($course, $section->section, array('navigation' => true));
83 if ($url) {
84 $title = html_writer::link($url, $title);
86 return $title;
89 /**
90 * Generate the section title to be displayed on the section page, without a link
92 * @param stdClass $section The course_section entry from DB
93 * @param stdClass $course The course entry from DB
94 * @return string HTML to output.
96 public function section_title_without_link($section, $course) {
97 return get_section_name($course, $section);
101 * Generate the edit control action menu
103 * @param array $controls The edit control items from section_edit_control_items
104 * @param stdClass $course The course entry from DB
105 * @param stdClass $section The course_section entry from DB
106 * @return string HTML to output.
108 protected function section_edit_control_menu($controls, $course, $section) {
109 $o = "";
110 if (!empty($controls)) {
111 $menu = new action_menu();
112 $menu->set_menu_trigger(get_string('edit'));
113 $menu->attributes['class'] .= ' section-actions';
114 foreach ($controls as $value) {
115 $url = empty($value['url']) ? '' : $value['url'];
116 $icon = empty($value['icon']) ? '' : $value['icon'];
117 $name = empty($value['name']) ? '' : $value['name'];
118 $attr = empty($value['attr']) ? array() : $value['attr'];
119 $class = empty($item['pixattr']['class']) ? '' : $item['pixattr']['class'];
120 $alt = empty($item['pixattr']['alt']) ? '' : $item['pixattr']['alt'];
121 $al = new action_menu_link_secondary(
122 new moodle_url($url),
123 new pix_icon($icon, $name, null, array('class' => "smallicon " . $class, 'alt' => $alt)),
124 $name,
125 $attr
127 $menu->add($al);
130 $o .= html_writer::div($this->render($menu), 'section_action_menu');
133 return $o;
137 * Generate the content to displayed on the right part of a section
138 * before course modules are included
140 * @param stdClass $section The course_section entry from DB
141 * @param stdClass $course The course entry from DB
142 * @param bool $onsectionpage true if being printed on a section page
143 * @return string HTML to output.
145 protected function section_right_content($section, $course, $onsectionpage) {
146 $o = $this->output->spacer();
148 $controls = $this->section_edit_control_items($course, $section, $onsectionpage);
149 $o .= $this->section_edit_control_menu($controls, $course, $section);
151 return $o;
155 * Generate the content to displayed on the left part of a section
156 * before course modules are included
158 * @param stdClass $section The course_section entry from DB
159 * @param stdClass $course The course entry from DB
160 * @param bool $onsectionpage true if being printed on a section page
161 * @return string HTML to output.
163 protected function section_left_content($section, $course, $onsectionpage) {
164 $o = $this->output->spacer();
166 if ($section->section != 0) {
167 // Only in the non-general sections.
168 if (course_get_format($course)->is_section_current($section)) {
169 $o = get_accesshide(get_string('currentsection', 'format_'.$course->format));
173 return $o;
177 * Generate the display of the header part of a section before
178 * course modules are included
180 * @param stdClass $section The course_section entry from DB
181 * @param stdClass $course The course entry from DB
182 * @param bool $onsectionpage true if being printed on a single-section page
183 * @param int $sectionreturn The section to return to after an action
184 * @return string HTML to output.
186 protected function section_header($section, $course, $onsectionpage, $sectionreturn=null) {
187 global $PAGE;
189 $o = '';
190 $currenttext = '';
191 $sectionstyle = '';
193 if ($section->section != 0) {
194 // Only in the non-general sections.
195 if (!$section->visible) {
196 $sectionstyle = ' hidden';
197 } else if (course_get_format($course)->is_section_current($section)) {
198 $sectionstyle = ' current';
202 $o.= html_writer::start_tag('li', array('id' => 'section-'.$section->section,
203 'class' => 'section main clearfix'.$sectionstyle, 'role'=>'region',
204 'aria-label'=> get_section_name($course, $section)));
206 // Create a span that contains the section title to be used to create the keyboard section move menu.
207 $o .= html_writer::tag('span', get_section_name($course, $section), array('class' => 'hidden sectionname'));
209 $leftcontent = $this->section_left_content($section, $course, $onsectionpage);
210 $o.= html_writer::tag('div', $leftcontent, array('class' => 'left side'));
212 $rightcontent = $this->section_right_content($section, $course, $onsectionpage);
213 $o.= html_writer::tag('div', $rightcontent, array('class' => 'right side'));
214 $o.= html_writer::start_tag('div', array('class' => 'content'));
216 // When not on a section page, we display the section titles except the general section if null
217 $hasnamenotsecpg = (!$onsectionpage && ($section->section != 0 || !is_null($section->name)));
219 // When on a section page, we only display the general section title, if title is not the default one
220 $hasnamesecpg = ($onsectionpage && ($section->section == 0 && !is_null($section->name)));
222 $classes = ' accesshide';
223 if ($hasnamenotsecpg || $hasnamesecpg) {
224 $classes = '';
226 $sectionname = html_writer::tag('span', $this->section_title($section, $course));
227 $o.= $this->output->heading($sectionname, 3, 'sectionname' . $classes);
229 $o.= html_writer::start_tag('div', array('class' => 'summary'));
230 $o.= $this->format_summary_text($section);
231 $o.= html_writer::end_tag('div');
233 $context = context_course::instance($course->id);
234 $o .= $this->section_availability_message($section,
235 has_capability('moodle/course:viewhiddensections', $context));
237 return $o;
241 * Generate the display of the footer part of a section
243 * @return string HTML to output.
245 protected function section_footer() {
246 $o = html_writer::end_tag('div');
247 $o.= html_writer::end_tag('li');
249 return $o;
253 * Generate the edit controls of a section
255 * @param stdClass $course The course entry from DB
256 * @param stdClass $section The course_section entry from DB
257 * @param bool $onsectionpage true if being printed on a section page
258 * @return array of links with edit controls
259 * @deprecated since Moodle 3.0 MDL-48947 - please do not use this function any more.
260 * @see format_section_renderer_base::section_edit_control_items()
262 protected function section_edit_controls($course, $section, $onsectionpage = false) {
263 global $PAGE;
265 if (!$PAGE->user_is_editing()) {
266 return array();
269 $controls = array();
270 $items = $this->section_edit_control_items($course, $section, $onsectionpage);
272 foreach ($items as $key => $item) {
273 $url = empty($item['url']) ? '' : $item['url'];
274 $icon = empty($item['icon']) ? '' : $item['icon'];
275 $name = empty($item['name']) ? '' : $item['name'];
276 $attr = empty($item['attr']) ? '' : $item['attr'];
277 $class = empty($item['pixattr']['class']) ? '' : $item['pixattr']['class'];
278 $alt = empty($item['pixattr']['alt']) ? '' : $item['pixattr']['alt'];
279 $controls[$key] = html_writer::link(
280 new moodle_url($url),
281 html_writer::empty_tag('img', array(
282 'src' => $this->output->pix_url($icon),
283 'class' => "icon " . $class,
284 'alt' => $alt
286 $attr);
289 debugging('section_edit_controls() is deprecated, please use section_edit_control_items() instead.', DEBUG_DEVELOPER);
290 return $controls;
294 * Generate the edit control items of a section
296 * @param stdClass $course The course entry from DB
297 * @param stdClass $section The course_section entry from DB
298 * @param bool $onsectionpage true if being printed on a section page
299 * @return array of edit control items
301 protected function section_edit_control_items($course, $section, $onsectionpage = false) {
302 global $PAGE;
304 if (!$PAGE->user_is_editing()) {
305 return array();
308 $coursecontext = context_course::instance($course->id);
309 $isstealth = isset($course->numsections) && ($section->section > $course->numsections);
311 if ($onsectionpage) {
312 $baseurl = course_get_url($course, $section->section);
313 } else {
314 $baseurl = course_get_url($course);
316 $baseurl->param('sesskey', sesskey());
318 $controls = array();
320 if (!$isstealth && has_capability('moodle/course:update', $coursecontext)) {
321 if ($section->section > 0
322 && get_string_manager()->string_exists('editsection', 'format_'.$course->format)) {
323 $streditsection = get_string('editsection', 'format_'.$course->format);
324 } else {
325 $streditsection = get_string('editsection');
328 $sectionreturn = $onsectionpage ? $section->section : 0;
329 $controls['edit'] = array(
330 'url' => new moodle_url('/course/editsection.php', array('id' => $section->id, 'sr' => $sectionreturn)),
331 'icon' => 'i/settings',
332 'name' => $streditsection,
333 'pixattr' => array('class' => '', 'alt' => $streditsection),
334 'attr' => array('class' => 'icon edit', 'title' => $streditsection));
337 if ($section->section) {
338 $url = clone($baseurl);
339 if (!$isstealth) {
340 if (has_capability('moodle/course:sectionvisibility', $coursecontext)) {
341 if ($section->visible) { // Show the hide/show eye.
342 $strhidefromothers = get_string('hidefromothers', 'format_'.$course->format);
343 $url->param('hide', $section->section);
344 $controls['visiblity'] = array(
345 'url' => $url,
346 'icon' => 'i/hide',
347 'name' => $strhidefromothers,
348 'pixattr' => array('class' => '', 'alt' => $strhidefromothers),
349 'attr' => array('class' => 'icon editing_showhide', 'title' => $strhidefromothers));
350 } else {
351 $strshowfromothers = get_string('showfromothers', 'format_'.$course->format);
352 $url->param('show', $section->section);
353 $controls['visiblity'] = array(
354 'url' => $url,
355 'icon' => 'i/show',
356 'name' => $strshowfromothers,
357 'pixattr' => array('class' => '', 'alt' => $strshowfromothers),
358 'attr' => array('class' => 'icon editing_showhide', 'title' => $strshowfromothers));
362 if (!$onsectionpage) {
363 if (has_capability('moodle/course:movesections', $coursecontext)) {
364 $url = clone($baseurl);
365 if ($section->section > 1) { // Add a arrow to move section up.
366 $url->param('section', $section->section);
367 $url->param('move', -1);
368 $strmoveup = get_string('moveup');
369 $controls['moveup'] = array(
370 'url' => $url,
371 'icon' => 'i/up',
372 'name' => $strmoveup,
373 'pixattr' => array('class' => '', 'alt' => $strmoveup),
374 'attr' => array('class' => 'icon moveup', 'title' => $strmoveup));
377 $url = clone($baseurl);
378 if ($section->section < $course->numsections) { // Add a arrow to move section down.
379 $url->param('section', $section->section);
380 $url->param('move', 1);
381 $strmovedown = get_string('movedown');
382 $controls['movedown'] = array(
383 'url' => $url,
384 'icon' => 'i/down',
385 'name' => $strmovedown,
386 'pixattr' => array('class' => '', 'alt' => $strmovedown),
387 'attr' => array('class' => 'icon movedown', 'title' => $strmovedown));
393 if (course_can_delete_section($course, $section)) {
394 if (get_string_manager()->string_exists('deletesection', 'format_'.$course->format)) {
395 $strdelete = get_string('deletesection', 'format_'.$course->format);
396 } else {
397 $strdelete = get_string('deletesection');
399 $url = new moodle_url('/course/editsection.php', array(
400 'id' => $section->id,
401 'sr' => $onsectionpage ? $section->section : 0,
402 'delete' => 1));
403 $controls['delete'] = array(
404 'url' => $url,
405 'icon' => 'i/delete',
406 'name' => $strdelete,
407 'pixattr' => array('class' => '', 'alt' => $strdelete),
408 'attr' => array('class' => 'icon delete', 'title' => $strdelete));
412 return $controls;
416 * Generate a summary of a section for display on the 'coruse index page'
418 * @param stdClass $section The course_section entry from DB
419 * @param stdClass $course The course entry from DB
420 * @param array $mods (argument not used)
421 * @return string HTML to output.
423 protected function section_summary($section, $course, $mods) {
424 $classattr = 'section main section-summary clearfix';
425 $linkclasses = '';
427 // If section is hidden then display grey section link
428 if (!$section->visible) {
429 $classattr .= ' hidden';
430 $linkclasses .= ' dimmed_text';
431 } else if (course_get_format($course)->is_section_current($section)) {
432 $classattr .= ' current';
435 $title = get_section_name($course, $section);
436 $o = '';
437 $o .= html_writer::start_tag('li', array('id' => 'section-'.$section->section,
438 'class' => $classattr, 'role'=>'region', 'aria-label'=> $title));
440 $o .= html_writer::tag('div', '', array('class' => 'left side'));
441 $o .= html_writer::tag('div', '', array('class' => 'right side'));
442 $o .= html_writer::start_tag('div', array('class' => 'content'));
444 if ($section->uservisible) {
445 $title = html_writer::tag('a', $title,
446 array('href' => course_get_url($course, $section->section), 'class' => $linkclasses));
448 $o .= $this->output->heading($title, 3, 'section-title');
450 $o.= html_writer::start_tag('div', array('class' => 'summarytext'));
451 $o.= $this->format_summary_text($section);
452 $o.= html_writer::end_tag('div');
453 $o.= $this->section_activity_summary($section, $course, null);
455 $context = context_course::instance($course->id);
456 $o .= $this->section_availability_message($section,
457 has_capability('moodle/course:viewhiddensections', $context));
459 $o .= html_writer::end_tag('div');
460 $o .= html_writer::end_tag('li');
462 return $o;
466 * Generate a summary of the activites in a section
468 * @param stdClass $section The course_section entry from DB
469 * @param stdClass $course the course record from DB
470 * @param array $mods (argument not used)
471 * @return string HTML to output.
473 protected function section_activity_summary($section, $course, $mods) {
474 $modinfo = get_fast_modinfo($course);
475 if (empty($modinfo->sections[$section->section])) {
476 return '';
479 // Generate array with count of activities in this section:
480 $sectionmods = array();
481 $total = 0;
482 $complete = 0;
483 $cancomplete = isloggedin() && !isguestuser();
484 $completioninfo = new completion_info($course);
485 foreach ($modinfo->sections[$section->section] as $cmid) {
486 $thismod = $modinfo->cms[$cmid];
488 if ($thismod->modname == 'label') {
489 // Labels are special (not interesting for students)!
490 continue;
493 if ($thismod->uservisible) {
494 if (isset($sectionmods[$thismod->modname])) {
495 $sectionmods[$thismod->modname]['name'] = $thismod->modplural;
496 $sectionmods[$thismod->modname]['count']++;
497 } else {
498 $sectionmods[$thismod->modname]['name'] = $thismod->modfullname;
499 $sectionmods[$thismod->modname]['count'] = 1;
501 if ($cancomplete && $completioninfo->is_enabled($thismod) != COMPLETION_TRACKING_NONE) {
502 $total++;
503 $completiondata = $completioninfo->get_data($thismod, true);
504 if ($completiondata->completionstate == COMPLETION_COMPLETE ||
505 $completiondata->completionstate == COMPLETION_COMPLETE_PASS) {
506 $complete++;
512 if (empty($sectionmods)) {
513 // No sections
514 return '';
517 // Output section activities summary:
518 $o = '';
519 $o.= html_writer::start_tag('div', array('class' => 'section-summary-activities mdl-right'));
520 foreach ($sectionmods as $mod) {
521 $o.= html_writer::start_tag('span', array('class' => 'activity-count'));
522 $o.= $mod['name'].': '.$mod['count'];
523 $o.= html_writer::end_tag('span');
525 $o.= html_writer::end_tag('div');
527 // Output section completion data
528 if ($total > 0) {
529 $a = new stdClass;
530 $a->complete = $complete;
531 $a->total = $total;
533 $o.= html_writer::start_tag('div', array('class' => 'section-summary-activities mdl-right'));
534 $o.= html_writer::tag('span', get_string('progresstotal', 'completion', $a), array('class' => 'activity-count'));
535 $o.= html_writer::end_tag('div');
538 return $o;
542 * If section is not visible, display the message about that ('Not available
543 * until...', that sort of thing). Otherwise, returns blank.
545 * For users with the ability to view hidden sections, it shows the
546 * information even though you can view the section and also may include
547 * slightly fuller information (so that teachers can tell when sections
548 * are going to be unavailable etc). This logic is the same as for
549 * activities.
551 * @param stdClass $section The course_section entry from DB
552 * @param bool $canviewhidden True if user can view hidden sections
553 * @return string HTML to output
555 protected function section_availability_message($section, $canviewhidden) {
556 global $CFG;
557 $o = '';
558 if (!$section->uservisible) {
559 // Note: We only get to this function if availableinfo is non-empty,
560 // so there is definitely something to print.
561 $formattedinfo = \core_availability\info::format_info(
562 $section->availableinfo, $section->course);
563 $o .= html_writer::div($formattedinfo, 'availabilityinfo');
564 } else if ($canviewhidden && !empty($CFG->enableavailability) && $section->visible) {
565 $ci = new \core_availability\info_section($section);
566 $fullinfo = $ci->get_full_information();
567 if ($fullinfo) {
568 $formattedinfo = \core_availability\info::format_info(
569 $fullinfo, $section->course);
570 $o .= html_writer::div($formattedinfo, 'availabilityinfo');
573 return $o;
577 * Show if something is on on the course clipboard (moving around)
579 * @param stdClass $course The course entry from DB
580 * @param int $sectionno The section number in the coruse which is being dsiplayed
581 * @return string HTML to output.
583 protected function course_activity_clipboard($course, $sectionno = null) {
584 global $USER;
586 $o = '';
587 // If currently moving a file then show the current clipboard.
588 if (ismoving($course->id)) {
589 $url = new moodle_url('/course/mod.php',
590 array('sesskey' => sesskey(),
591 'cancelcopy' => true,
592 'sr' => $sectionno,
596 $o.= html_writer::start_tag('div', array('class' => 'clipboard'));
597 $o.= strip_tags(get_string('activityclipboard', '', $USER->activitycopyname));
598 $o.= ' ('.html_writer::link($url, get_string('cancel')).')';
599 $o.= html_writer::end_tag('div');
602 return $o;
606 * Generate next/previous section links for naviation
608 * @param stdClass $course The course entry from DB
609 * @param array $sections The course_sections entries from the DB
610 * @param int $sectionno The section number in the coruse which is being dsiplayed
611 * @return array associative array with previous and next section link
613 protected function get_nav_links($course, $sections, $sectionno) {
614 // FIXME: This is really evil and should by using the navigation API.
615 $course = course_get_format($course)->get_course();
616 $canviewhidden = has_capability('moodle/course:viewhiddensections', context_course::instance($course->id))
617 or !$course->hiddensections;
619 $links = array('previous' => '', 'next' => '');
620 $back = $sectionno - 1;
621 while ($back > 0 and empty($links['previous'])) {
622 if ($canviewhidden || $sections[$back]->uservisible) {
623 $params = array();
624 if (!$sections[$back]->visible) {
625 $params = array('class' => 'dimmed_text');
627 $previouslink = html_writer::tag('span', $this->output->larrow(), array('class' => 'larrow'));
628 $previouslink .= get_section_name($course, $sections[$back]);
629 $links['previous'] = html_writer::link(course_get_url($course, $back), $previouslink, $params);
631 $back--;
634 $forward = $sectionno + 1;
635 while ($forward <= $course->numsections and empty($links['next'])) {
636 if ($canviewhidden || $sections[$forward]->uservisible) {
637 $params = array();
638 if (!$sections[$forward]->visible) {
639 $params = array('class' => 'dimmed_text');
641 $nextlink = get_section_name($course, $sections[$forward]);
642 $nextlink .= html_writer::tag('span', $this->output->rarrow(), array('class' => 'rarrow'));
643 $links['next'] = html_writer::link(course_get_url($course, $forward), $nextlink, $params);
645 $forward++;
648 return $links;
652 * Generate the header html of a stealth section
654 * @param int $sectionno The section number in the coruse which is being dsiplayed
655 * @return string HTML to output.
657 protected function stealth_section_header($sectionno) {
658 $o = '';
659 $o.= html_writer::start_tag('li', array('id' => 'section-'.$sectionno, 'class' => 'section main clearfix orphaned hidden'));
660 $o.= html_writer::tag('div', '', array('class' => 'left side'));
661 $course = course_get_format($this->page->course)->get_course();
662 $section = course_get_format($this->page->course)->get_section($sectionno);
663 $rightcontent = $this->section_right_content($section, $course, false);
664 $o.= html_writer::tag('div', $rightcontent, array('class' => 'right side'));
665 $o.= html_writer::start_tag('div', array('class' => 'content'));
666 $o.= $this->output->heading(get_string('orphanedactivitiesinsectionno', '', $sectionno), 3, 'sectionname');
667 return $o;
671 * Generate footer html of a stealth section
673 * @return string HTML to output.
675 protected function stealth_section_footer() {
676 $o = html_writer::end_tag('div');
677 $o.= html_writer::end_tag('li');
678 return $o;
682 * Generate the html for a hidden section
684 * @param int $sectionno The section number in the coruse which is being dsiplayed
685 * @param int|stdClass $courseorid The course to get the section name for (object or just course id)
686 * @return string HTML to output.
688 protected function section_hidden($sectionno, $courseorid = null) {
689 if ($courseorid) {
690 $sectionname = get_section_name($courseorid, $sectionno);
691 $strnotavailable = get_string('notavailablecourse', '', $sectionname);
692 } else {
693 $strnotavailable = get_string('notavailable');
696 $o = '';
697 $o.= html_writer::start_tag('li', array('id' => 'section-'.$sectionno, 'class' => 'section main clearfix hidden'));
698 $o.= html_writer::tag('div', '', array('class' => 'left side'));
699 $o.= html_writer::tag('div', '', array('class' => 'right side'));
700 $o.= html_writer::start_tag('div', array('class' => 'content'));
701 $o.= html_writer::tag('div', $strnotavailable);
702 $o.= html_writer::end_tag('div');
703 $o.= html_writer::end_tag('li');
704 return $o;
708 * Generate the html for the 'Jump to' menu on a single section page.
710 * @param stdClass $course The course entry from DB
711 * @param array $sections The course_sections entries from the DB
712 * @param $displaysection the current displayed section number.
714 * @return string HTML to output.
716 protected function section_nav_selection($course, $sections, $displaysection) {
717 global $CFG;
718 $o = '';
719 $sectionmenu = array();
720 $sectionmenu[course_get_url($course)->out(false)] = get_string('maincoursepage');
721 $modinfo = get_fast_modinfo($course);
722 $section = 1;
723 while ($section <= $course->numsections) {
724 $thissection = $modinfo->get_section_info($section);
725 $showsection = $thissection->uservisible or !$course->hiddensections;
726 if (($showsection) && ($section != $displaysection) && ($url = course_get_url($course, $section))) {
727 $sectionmenu[$url->out(false)] = get_section_name($course, $section);
729 $section++;
732 $select = new url_select($sectionmenu, '', array('' => get_string('jumpto')));
733 $select->class = 'jumpmenu';
734 $select->formid = 'sectionmenu';
735 $o .= $this->output->render($select);
737 return $o;
741 * Output the html for a single section page .
743 * @param stdClass $course The course entry from DB
744 * @param array $sections (argument not used)
745 * @param array $mods (argument not used)
746 * @param array $modnames (argument not used)
747 * @param array $modnamesused (argument not used)
748 * @param int $displaysection The section number in the course which is being displayed
750 public function print_single_section_page($course, $sections, $mods, $modnames, $modnamesused, $displaysection) {
751 global $PAGE;
753 $modinfo = get_fast_modinfo($course);
754 $course = course_get_format($course)->get_course();
756 // Can we view the section in question?
757 if (!($sectioninfo = $modinfo->get_section_info($displaysection))) {
758 // This section doesn't exist
759 print_error('unknowncoursesection', 'error', null, $course->fullname);
760 return;
763 if (!$sectioninfo->uservisible) {
764 if (!$course->hiddensections) {
765 echo $this->start_section_list();
766 echo $this->section_hidden($displaysection, $course->id);
767 echo $this->end_section_list();
769 // Can't view this section.
770 return;
773 // Copy activity clipboard..
774 echo $this->course_activity_clipboard($course, $displaysection);
775 $thissection = $modinfo->get_section_info(0);
776 if ($thissection->summary or !empty($modinfo->sections[0]) or $PAGE->user_is_editing()) {
777 echo $this->start_section_list();
778 echo $this->section_header($thissection, $course, true, $displaysection);
779 echo $this->courserenderer->course_section_cm_list($course, $thissection, $displaysection);
780 echo $this->courserenderer->course_section_add_cm_control($course, 0, $displaysection);
781 echo $this->section_footer();
782 echo $this->end_section_list();
785 // Start single-section div
786 echo html_writer::start_tag('div', array('class' => 'single-section'));
788 // The requested section page.
789 $thissection = $modinfo->get_section_info($displaysection);
791 // Title with section navigation links.
792 $sectionnavlinks = $this->get_nav_links($course, $modinfo->get_section_info_all(), $displaysection);
793 $sectiontitle = '';
794 $sectiontitle .= html_writer::start_tag('div', array('class' => 'section-navigation navigationtitle'));
795 $sectiontitle .= html_writer::tag('span', $sectionnavlinks['previous'], array('class' => 'mdl-left'));
796 $sectiontitle .= html_writer::tag('span', $sectionnavlinks['next'], array('class' => 'mdl-right'));
797 // Title attributes
798 $classes = 'sectionname';
799 if (!$thissection->visible) {
800 $classes .= ' dimmed_text';
802 $sectionname = html_writer::tag('span', $this->section_title_without_link($thissection, $course));
803 $sectiontitle .= $this->output->heading($sectionname, 3, $classes);
805 $sectiontitle .= html_writer::end_tag('div');
806 echo $sectiontitle;
808 // Now the list of sections..
809 echo $this->start_section_list();
811 echo $this->section_header($thissection, $course, true, $displaysection);
812 // Show completion help icon.
813 $completioninfo = new completion_info($course);
814 echo $completioninfo->display_help_icon();
816 echo $this->courserenderer->course_section_cm_list($course, $thissection, $displaysection);
817 echo $this->courserenderer->course_section_add_cm_control($course, $displaysection, $displaysection);
818 echo $this->section_footer();
819 echo $this->end_section_list();
821 // Display section bottom navigation.
822 $sectionbottomnav = '';
823 $sectionbottomnav .= html_writer::start_tag('div', array('class' => 'section-navigation mdl-bottom'));
824 $sectionbottomnav .= html_writer::tag('span', $sectionnavlinks['previous'], array('class' => 'mdl-left'));
825 $sectionbottomnav .= html_writer::tag('span', $sectionnavlinks['next'], array('class' => 'mdl-right'));
826 $sectionbottomnav .= html_writer::tag('div', $this->section_nav_selection($course, $sections, $displaysection),
827 array('class' => 'mdl-align'));
828 $sectionbottomnav .= html_writer::end_tag('div');
829 echo $sectionbottomnav;
831 // Close single-section div.
832 echo html_writer::end_tag('div');
836 * Output the html for a multiple section page
838 * @param stdClass $course The course entry from DB
839 * @param array $sections (argument not used)
840 * @param array $mods (argument not used)
841 * @param array $modnames (argument not used)
842 * @param array $modnamesused (argument not used)
844 public function print_multiple_section_page($course, $sections, $mods, $modnames, $modnamesused) {
845 global $PAGE;
847 $modinfo = get_fast_modinfo($course);
848 $course = course_get_format($course)->get_course();
850 $context = context_course::instance($course->id);
851 // Title with completion help icon.
852 $completioninfo = new completion_info($course);
853 echo $completioninfo->display_help_icon();
854 echo $this->output->heading($this->page_title(), 2, 'accesshide');
856 // Copy activity clipboard..
857 echo $this->course_activity_clipboard($course, 0);
859 // Now the list of sections..
860 echo $this->start_section_list();
862 foreach ($modinfo->get_section_info_all() as $section => $thissection) {
863 if ($section == 0) {
864 // 0-section is displayed a little different then the others
865 if ($thissection->summary or !empty($modinfo->sections[0]) or $PAGE->user_is_editing()) {
866 echo $this->section_header($thissection, $course, false, 0);
867 echo $this->courserenderer->course_section_cm_list($course, $thissection, 0);
868 echo $this->courserenderer->course_section_add_cm_control($course, 0, 0);
869 echo $this->section_footer();
871 continue;
873 if ($section > $course->numsections) {
874 // activities inside this section are 'orphaned', this section will be printed as 'stealth' below
875 continue;
877 // Show the section if the user is permitted to access it, OR if it's not available
878 // but there is some available info text which explains the reason & should display.
879 $showsection = $thissection->uservisible ||
880 ($thissection->visible && !$thissection->available &&
881 !empty($thissection->availableinfo));
882 if (!$showsection) {
883 // If the hiddensections option is set to 'show hidden sections in collapsed
884 // form', then display the hidden section message - UNLESS the section is
885 // hidden by the availability system, which is set to hide the reason.
886 if (!$course->hiddensections && $thissection->available) {
887 echo $this->section_hidden($section, $course->id);
890 continue;
893 if (!$PAGE->user_is_editing() && $course->coursedisplay == COURSE_DISPLAY_MULTIPAGE) {
894 // Display section summary only.
895 echo $this->section_summary($thissection, $course, null);
896 } else {
897 echo $this->section_header($thissection, $course, false, 0);
898 if ($thissection->uservisible) {
899 echo $this->courserenderer->course_section_cm_list($course, $thissection, 0);
900 echo $this->courserenderer->course_section_add_cm_control($course, $section, 0);
902 echo $this->section_footer();
906 if ($PAGE->user_is_editing() and has_capability('moodle/course:update', $context)) {
907 // Print stealth sections if present.
908 foreach ($modinfo->get_section_info_all() as $section => $thissection) {
909 if ($section <= $course->numsections or empty($modinfo->sections[$section])) {
910 // this is not stealth section or it is empty
911 continue;
913 echo $this->stealth_section_header($section);
914 echo $this->courserenderer->course_section_cm_list($course, $thissection, 0);
915 echo $this->stealth_section_footer();
918 echo $this->end_section_list();
920 echo html_writer::start_tag('div', array('id' => 'changenumsections', 'class' => 'mdl-right'));
922 // Increase number of sections.
923 $straddsection = get_string('increasesections', 'moodle');
924 $url = new moodle_url('/course/changenumsections.php',
925 array('courseid' => $course->id,
926 'increase' => true,
927 'sesskey' => sesskey()));
928 $icon = $this->output->pix_icon('t/switch_plus', $straddsection);
929 echo html_writer::link($url, $icon.get_accesshide($straddsection), array('class' => 'increase-sections'));
931 if ($course->numsections > 0) {
932 // Reduce number of sections sections.
933 $strremovesection = get_string('reducesections', 'moodle');
934 $url = new moodle_url('/course/changenumsections.php',
935 array('courseid' => $course->id,
936 'increase' => false,
937 'sesskey' => sesskey()));
938 $icon = $this->output->pix_icon('t/switch_minus', $strremovesection);
939 echo html_writer::link($url, $icon.get_accesshide($strremovesection), array('class' => 'reduce-sections'));
942 echo html_writer::end_tag('div');
943 } else {
944 echo $this->end_section_list();
950 * Generate html for a section summary text
952 * @param stdClass $section The course_section entry from DB
953 * @return string HTML to output.
955 protected function format_summary_text($section) {
956 $context = context_course::instance($section->course);
957 $summarytext = file_rewrite_pluginfile_urls($section->summary, 'pluginfile.php',
958 $context->id, 'course', 'section', $section->id);
960 $options = new stdClass();
961 $options->noclean = true;
962 $options->overflowdiv = true;
963 return format_text($summarytext, $section->summaryformat, $options);