MDL-24419 (3): Add new parameter to format_float for shorter display
[moodle.git] / course / format / renderer.php
CommitLineData
1804b7c1
DP
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.
13//
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/>.
16
17/**
18 * Base renderer for outputting course formats.
19 *
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
24 */
25
26defined('MOODLE_INTERNAL') || die();
27
28
29/**
a8f02a34 30 * This is a convenience renderer which can be used by section based formats
3df72f8c 31 * to reduce code duplication. It is not necessary for all course formats to
a8f02a34 32 * use this and its likely to change in future releases.
1804b7c1
DP
33 *
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
38 */
a8f02a34 39abstract class format_section_renderer_base extends plugin_renderer_base {
1804b7c1
DP
40
41 /**
42 * Generate the starting container html for a list of sections
43 * @return string HTML to output.
44 */
cbf44997 45 abstract protected function start_section_list();
1804b7c1
DP
46
47 /**
48 * Generate the closing container html for a list of sections
49 * @return string HTML to output.
50 */
cbf44997 51 abstract protected function end_section_list();
1804b7c1
DP
52
53 /**
54 * Generate the title for this section page
55 * @return string the page title
56 */
cbf44997 57 abstract protected function page_title();
1804b7c1 58
a830d866
DP
59 /**
60 * Generate the content to displayed on the right part of a section
a830d866 61 * before course modules are included
96e12851 62 *
a830d866
DP
63 * @param stdClass $section The course_section entry from DB
64 * @param stdClass $course The course entry from DB
65 * @param bool $onsectionpage true if being printed on a section page
66 * @return string HTML to output.
67 */
cbf44997 68 protected function section_right_content($section, $course, $onsectionpage) {
a830d866
DP
69 $o = $this->output->spacer();
70
71 if ($section->section != 0) {
72 $controls = $this->section_edit_controls($course, $section, $onsectionpage);
73 if (!empty($controls)) {
74 $o = implode('<br />', $controls);
75 }
76 }
77
78 return $o;
79 }
80
81 /**
82 * Generate the content to displayed on the left part of a section
a830d866 83 * before course modules are included
96e12851 84 *
a830d866
DP
85 * @param stdClass $section The course_section entry from DB
86 * @param stdClass $course The course entry from DB
87 * @param bool $onsectionpage true if being printed on a section page
88 * @return string HTML to output.
89 */
cbf44997 90 protected function section_left_content($section, $course, $onsectionpage) {
a830d866
DP
91 $o = $this->output->spacer();
92
93 if ($section->section != 0) {
94 // Only in the non-general sections.
95 if ($course->marker == $section->section) {
96 $o = get_accesshide(get_string('currentsection', 'format_'.$course->format));
97 }
98 }
99
100 return $o;
101 }
102
1804b7c1
DP
103 /**
104 * Generate the display of the header part of a section before
105 * course modules are included
106 *
107 * @param stdClass $section The course_section entry from DB
108 * @param stdClass $course The course entry from DB
109 * @param bool $onsectionpage true if being printed on a section page
110 * @return string HTML to output.
111 */
cbf44997 112 protected function section_header($section, $course, $onsectionpage) {
1804b7c1
DP
113 global $PAGE;
114
115 $o = '';
116 $currenttext = '';
117 $sectionstyle = '';
1804b7c1
DP
118 $linktitle = false;
119
96e12851 120 if ($section->section != 0) {
1804b7c1
DP
121 // Only in the non-general sections.
122 if (!$section->visible) {
123 $sectionstyle = ' hidden';
124 } else if ($course->marker == $section->section) {
125 $sectionstyle = ' current';
1804b7c1
DP
126 }
127 $linktitle = ($course->coursedisplay == COURSE_DISPLAY_MULTIPAGE);
128 }
129
130 $o.= html_writer::start_tag('li', array('id' => 'section-'.$section->section,
131 'class' => 'section main clearfix'.$sectionstyle));
a830d866
DP
132
133 $leftcontent = $this->section_left_content($section, $course, $onsectionpage);
1804b7c1 134 $o.= html_writer::tag('div', $leftcontent, array('class' => 'left side'));
a830d866
DP
135
136 $rightcontent = $this->section_right_content($section, $course, $onsectionpage);
1804b7c1
DP
137 $o.= html_writer::tag('div', $rightcontent, array('class' => 'right side'));
138 $o.= html_writer::start_tag('div', array('class' => 'content'));
139
140 if (!$onsectionpage) {
141 $title = get_section_name($course, $section);
142 if ($linktitle) {
143 $title = html_writer::link(course_get_url($course, $section->section), $title);
144 }
145 $o.= $this->output->heading($title, 3, 'sectionname');
146 }
147
148 $o.= html_writer::start_tag('div', array('class' => 'summary'));
7cb8bfdb 149 $o.= $this->format_summary_text($section);
1804b7c1 150
7cb8bfdb 151 $context = context_course::instance($course->id);
1804b7c1
DP
152 if ($PAGE->user_is_editing() && has_capability('moodle/course:update', $context)) {
153 $url = new moodle_url('/course/editsection.php', array('id'=>$section->id));
154
155 if ($onsectionpage) {
156 $url->param('sectionreturn', 1);
157 }
158
159 $o.= html_writer::link($url,
160 html_writer::empty_tag('img', array('src' => $this->output->pix_url('t/edit'), 'class' => 'iconsmall edit')),
161 array('title' => get_string('editsummary')));
162 }
163 $o.= html_writer::end_tag('div');
164
165 return $o;
166 }
167
168 /**
169 * Generate the display of the footer part of a section
170 *
171 * @return string HTML to output.
172 */
cbf44997 173 protected function section_footer() {
1804b7c1
DP
174 $o = html_writer::end_tag('div');
175 $o.= html_writer::end_tag('li');
176
177 return $o;
178 }
179
180 /**
181 * Generate the edit controls of a section
182 *
183 * @param stdClass $course The course entry from DB
184 * @param stdClass $section The course_section entry from DB
185 * @param bool $onsectionpage true if being printed on a section page
186 * @return array of links with edit controls
187 */
cbf44997 188 protected function section_edit_controls($course, $section, $onsectionpage = false) {
1804b7c1
DP
189 global $PAGE;
190
191 if (!$PAGE->user_is_editing()) {
192 return array();
193 }
194
195 if (!has_capability('moodle/course:update', context_course::instance($course->id))) {
196 return array();
197 }
198
199 if ($onsectionpage) {
200 $baseurl = course_get_url($course, $section->section);
201 } else {
202 $baseurl = course_get_url($course);
203 }
204 $baseurl->param('sesskey', sesskey());
205
206 $controls = array();
207
208 $url = clone($baseurl);
209 if ($section->visible) { // Show the hide/show eye.
210 $strhidefromothers = get_string('hidefromothers', 'format_'.$course->format);
211 $url->param('hide', $section->section);
212 $controls[] = html_writer::link($url,
213 html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/hide'),
214 'class' => 'icon hide', 'alt' => $strhidefromothers)),
215 array('title' => $strhidefromothers, 'class' => 'editing_showhide'));
216 } else {
217 $strshowfromothers = get_string('showfromothers', 'format_'.$course->format);
218 $url->param('show', $section->section);
219 $controls[] = html_writer::link($url,
220 html_writer::empty_tag('img', array('src' => $this->output->pix_url('i/show'),
221 'class' => 'icon hide', 'alt' => $strshowfromothers)),
222 array('title' => $strshowfromothers, 'class' => 'editing_showhide'));
223 }
224
225 if (!$onsectionpage) {
226 $url = clone($baseurl);
227 if ($section->section > 1) { // Add a arrow to move section up.
228 $url->param('section', $section->section);
229 $url->param('move', -1);
230 $strmoveup = get_string('moveup');
231
232 $controls[] = html_writer::link($url,
233 html_writer::empty_tag('img', array('src' => $this->output->pix_url('t/up'),
234 'class' => 'icon up', 'alt' => $strmoveup)),
235 array('title' => $strmoveup, 'class' => 'moveup'));
236 }
237
238 $url = clone($baseurl);
239 if ($section->section < $course->numsections) { // Add a arrow to move section down.
240 $url->param('section', $section->section);
241 $url->param('move', 1);
242 $strmovedown = get_string('movedown');
243
244 $controls[] = html_writer::link($url,
245 html_writer::empty_tag('img', array('src' => $this->output->pix_url('t/down'),
246 'class' => 'icon down', 'alt' => $strmovedown)),
247 array('title' => $strmovedown, 'class' => 'movedown'));
248 }
249 }
250
251 return $controls;
252 }
253
254 /**
255 * Generate a summary of a section for display on the 'coruse index page'
256 *
257 * @param stdClass $section The course_section entry from DB
258 * @param stdClass $course The course entry from DB
259 * @return string HTML to output.
260 */
cbf44997 261 protected function section_summary($section, $course) {
1804b7c1
DP
262
263 $o = '';
a60cc6e1
DP
264 $o.= html_writer::start_tag('li', array('id' => 'section-'.$section->section,
265 'class' => 'section-summary clearfix'));
1804b7c1
DP
266
267 $title = get_section_name($course, $section);
1804b7c1
DP
268 $o.= html_writer::start_tag('a', array('href' => course_get_url($course, $section->section)));
269 $o.= $this->output->heading($title, 3, 'header section-title');
270 $o.= html_writer::end_tag('a');
271
272 $o.= html_writer::start_tag('div', array('class' => 'summarytext'));
7cb8bfdb 273 $o.= $this->format_summary_text($section);
1804b7c1 274 $o.= html_writer::end_tag('div');
1804b7c1
DP
275 $o.= html_writer::end_tag('li');
276
277 return $o;
278 }
279
280 /**
281 * Show if something is on on the course clipboard (moving around)
282 *
283 * @param stdClass $course The course entry from DB
284 * @param int $sectionno The section number in the coruse which is being dsiplayed
285 * @return string HTML to output.
286 */
cbf44997 287 protected function course_activity_clipboard($course, $sectionno = 0) {
1804b7c1
DP
288 global $USER;
289
290 $o = '';
291 // If currently moving a file then show the current clipboard.
292 if (ismoving($course->id)) {
293 $url = new moodle_url('/course/mod.php',
294 array('sesskey' => sesskey(),
295 'cancelcopy' => true,
296 'sr' => $sectionno,
297 )
298 );
299
300 $strcancel= get_string('cancel');
301
302 $o.= html_writer::start_tag('li', array('class' => 'clipboard'));
303 $o.= strip_tags(get_string('activityclipboard', '', $USER->activitycopyname));
304 $o.= ' ('.html_writer::link($url, get_string('cancel')).')';
305 $o.= html_writer::end_tag('li');
306 }
307
308 return $o;
309 }
310
311 /**
312 * Generate next/previous section links for naviation
313 *
314 * @param stdClass $course The course entry from DB
315 * @param array $sections The course_sections entries from the DB
316 * @param int $sectionno The section number in the coruse which is being dsiplayed
317 * @return string HTML to output.
318 */
cbf44997 319 protected function get_nav_links($course, $sections, $sectionno) {
1804b7c1
DP
320 // FIXME: This is really evil and should by using the navigation API.
321 $canviewhidden = has_capability('moodle/course:viewhiddensections', context_course::instance($course->id))
322 or !$course->hiddensections;
323
324 $links = array('previous' => '', 'next' => '');
325 $back = $sectionno - 1;
326 while ($back > 0 and empty($links['previous'])) {
327 if ($canviewhidden || $sections[$back]->visible) {
328 $links['previous'] = html_writer::link(course_get_url($course, $back),
329 $this->output->larrow().$this->output->spacer().get_section_name($course, $sections[$back]));
330 }
331 $back--;
332 }
333
334 $forward = $sectionno + 1;
335 while ($forward <= $course->numsections and empty($links['next'])) {
336 if ($canviewhidden || $sections[$forward]->visible) {
337 $links['next'] = html_writer::link(course_get_url($course, $forward),
338 get_section_name($course, $sections[$forward]).$this->output->spacer().$this->output->rarrow());
339 }
340 $forward++;
341 }
342
343 $o = '';
344 $o.= html_writer::start_tag('div', array('class' => 'section-navigation yui3-g'));
345 $o.= html_writer::tag('div', $links['previous'], array('class' => 'yui3-u'));
346 $o.= html_writer::tag('div', $links['next'], array('class' => 'right yui3-u'));
347 $o.= html_writer::end_tag('div');
348
349 return $o;
350 }
351
352 /**
353 * Generate the header html of a stealth section
354 *
355 * @param int $sectionno The section number in the coruse which is being dsiplayed
356 * @return string HTML to output.
357 */
cbf44997 358 protected function stealth_section_header($sectionno) {
1804b7c1
DP
359 $o = '';
360 $o.= html_writer::start_tag('li', array('id' => 'section-'.$sectionno, 'class' => 'section main clearfix orphaned hidden'));
361 $o.= html_writer::tag('div', '', array('class' => 'left side'));
362 $o.= html_writer::tag('div', '', array('class' => 'right side'));
363 $o.= html_writer::start_tag('div', array('class' => 'content'));
364 $o.= $this->output->heading(get_string('orphanedactivities'), 3, 'sectionname');
365 return $o;
366 }
367
368 /**
369 * Generate footer html of a stealth section
370 *
371 * @return string HTML to output.
372 */
cbf44997 373 protected function stealth_section_footer() {
1804b7c1
DP
374 $o = html_writer::end_tag('div');
375 $o.= html_writer::end_tag('li');
376 return $o;
377 }
378
379 /**
380 * Generate the html for a hidden section
381 *
382 * @param int $sectionno The section number in the coruse which is being dsiplayed
383 * @return string HTML to output.
384 */
cbf44997 385 protected function section_hidden($sectionno) {
1804b7c1
DP
386 $o = '';
387 $o.= html_writer::start_tag('li', array('id' => 'section-'.$sectionno, 'class' => 'section main clearfix hidden'));
388 $o.= html_writer::tag('div', '', array('class' => 'left side'));
389 $o.= html_writer::tag('div', '', array('class' => 'right side'));
390 $o.= html_writer::start_tag('div', array('class' => 'content'));
391 $o.= get_string('notavailable');
392 $o.= html_writer::end_tag('div');
393 $o.= html_writer::end_tag('li');
394 return $o;
395 }
396
397 /**
398 * Output the html for a single section page .
399 *
400 * @param stdClass $course The course entry from DB
401 * @param array $sections The course_sections entries from the DB
402 * @param array $mods used for print_section()
403 * @param array $modnames used for print_section()
404 * @param array $modnamesused used for print_section()
405 * @param int $displaysection The section number in the course which is being displayed
406 */
407 public function print_single_section_page($course, $sections, $mods, $modnames, $modnamesused, $displaysection) {
408 global $PAGE;
409
1804b7c1
DP
410 // Can we view the section in question?
411 $context = context_course::instance($course->id);
412 $canviewhidden = has_capability('moodle/course:viewhiddensections', $context);
413
0c053c53
ARN
414 if (!isset($sections[$displaysection])) {
415 // This section doesn't exist
416 print_error('unknowncoursesection', 'error', null, $course->fullname);
417 return;
418 }
419
1804b7c1
DP
420 if (!$sections[$displaysection]->visible && !$canviewhidden) {
421 if (!$course->hiddensections) {
422 echo $this->start_section_list();
423 echo $this->section_hidden($displaysection);
424 echo $this->end_section_list();
425 echo $sectionnavlinks;
426 }
427 // Can't view this section.
428 return;
429 }
430
243b7003
DP
431 // General section if non-empty.
432 $thissection = $sections[0];
433 if ($thissection->summary or $thissection->sequence or $PAGE->user_is_editing()) {
434 echo $this->start_section_list();
435 echo $this->section_header($thissection, $course, true);
436 print_section($course, $thissection, $mods, $modnamesused, true);
437 if ($PAGE->user_is_editing()) {
438 print_section_add_menus($course, 0, $modnames);
439 }
440 echo $this->section_footer();
441 echo $this->end_section_list();
442 }
443
444 // Section next/previous links.
445 $sectionnavlinks = $this->get_nav_links($course, $sections, $displaysection);
446 echo $sectionnavlinks;
447
448
1804b7c1
DP
449 // Title with completion help icon.
450 $completioninfo = new completion_info($course);
451 echo $completioninfo->display_help_icon();
452 $title = get_section_name($course, $sections[$displaysection]);
453 echo $this->output->heading($title, 2, 'headingblock header outline');
454
455 // Copy activity clipboard..
456 echo $this->course_activity_clipboard($course, $displaysection);
457
458 // Now the list of sections..
459 echo $this->start_section_list();
460
1804b7c1
DP
461 // The requested section page.
462 $thissection = $sections[$displaysection];
463 echo $this->section_header($thissection, $course, true);
464 print_section($course, $thissection, $mods, $modnamesused, true);
465 if ($PAGE->user_is_editing()) {
466 print_section_add_menus($course, $displaysection, $modnames);
467 }
468 echo $this->section_footer();
469 echo $sectionnavlinks;
470 echo $this->end_section_list();
471 }
472
473 /**
474 * Output the html for a multiple section page
475 *
476 * @param stdClass $course The course entry from DB
477 * @param array $sections The course_sections entries from the DB
478 * @param array $mods used for print_section()
479 * @param array $modnames used for print_section()
480 * @param array $modnamesused used for print_section()
481 */
482 public function print_multiple_section_page($course, $sections, $mods, $modnames, $modnamesused) {
483 global $PAGE;
484
485 $context = context_course::instance($course->id);
486 // Title with completion help icon.
487 $completioninfo = new completion_info($course);
488 echo $completioninfo->display_help_icon();
803e36e1 489 echo $this->output->heading($this->page_title(), 2, 'accesshide');
1804b7c1
DP
490
491 // Copy activity clipboard..
492 echo $this->course_activity_clipboard($course);
493
494 // Now the list of sections..
495 echo $this->start_section_list();
496
497 // General section if non-empty.
498 $thissection = $sections[0];
499 unset($sections[0]);
500 if ($thissection->summary or $thissection->sequence or $PAGE->user_is_editing()) {
501 echo $this->section_header($thissection, $course, true);
502 print_section($course, $thissection, $mods, $modnamesused, true);
503 if ($PAGE->user_is_editing()) {
504 print_section_add_menus($course, 0, $modnames);
505 }
506 echo $this->section_footer();
507 }
508
509 $canviewhidden = has_capability('moodle/course:viewhiddensections', $context);
510 for ($section = 1; $section <= $course->numsections; $section++) {
511 if (!empty($sections[$section])) {
512 $thissection = $sections[$section];
513 } else {
514 // This will create a course section if it doesn't exist..
515 $thissection = get_course_section($section, $course->id);
516 }
517 $showsection = ($canviewhidden or $thissection->visible or !$course->hiddensections);
518 if (!$thissection->visible && !$canviewhidden) {
519 if (!$course->hiddensections) {
520 echo $this->section_hidden($section);
521 }
522
523 unset($sections[$section]);
524 continue;
525 }
526
527 if (!$PAGE->user_is_editing() && $course->coursedisplay == COURSE_DISPLAY_MULTIPAGE) {
528 // Display section summary only.
529 echo $this->section_summary($thissection, $course);
530 } else {
531 echo $this->section_header($thissection, $course, false);
532 print_section($course, $thissection, $mods, $modnamesused);
533 if ($PAGE->user_is_editing()) {
534 print_section_add_menus($course, $section, $modnames);
535 }
536 echo $this->section_footer();
537 }
538
539 unset($sections[$section]);
540 }
541
542 if ($PAGE->user_is_editing() and has_capability('moodle/course:update', $context)) {
543 // Print stealth sections if present.
544 $modinfo = get_fast_modinfo($course);
545 foreach ($sections as $section => $thissection) {
546 if (empty($modinfo->sections[$section])) {
547 continue;
548 }
549 echo $this->stealth_section_header($section);
550 print_section($course, $thissection, $mods, $modnamesused);
551 echo $this->stealth_section_footer();
552 }
1abf1253 553
575826c7
ARN
554 echo $this->end_section_list();
555
3a35a9ff
DP
556 echo html_writer::start_tag('div', array('class' => 'mdl-right'));
557
558 // Increase number of sections.
559 $straddsection = get_string('increasesections', 'moodle');
560 $url = new moodle_url('/course/changenumsections.php',
561 array('courseid' => $course->id,
562 'increase' => true,
563 'sesskey' => sesskey()));
564 $icon = $this->output->pix_icon('t/switch_plus', $straddsection);
565 echo html_writer::link($url, $icon.get_accesshide($straddsection), array('class' => 'increase-sections'));
566
567 if ($course->numsections > 0) {
568 // Reduce number of sections sections.
569 $strremovesection = get_string('reducesections', 'moodle');
570 $url = new moodle_url('/course/changenumsections.php',
571 array('courseid' => $course->id,
572 'increase' => false,
573 'sesskey' => sesskey()));
574 $icon = $this->output->pix_icon('t/switch_minus', $strremovesection);
575 echo html_writer::link($url, $icon.get_accesshide($strremovesection), array('class' => 'reduce-sections'));
576 }
577
1abf1253 578 echo html_writer::end_tag('div');
575826c7
ARN
579 } else {
580 echo $this->end_section_list();
1804b7c1
DP
581 }
582
1804b7c1 583 }
7cb8bfdb
DP
584
585 /**
586 * Generate html for a section summary text
587 *
588 * @param stdClass $section The course_section entry from DB
589 * @return string HTML to output.
590 */
591 protected function format_summary_text($section) {
592 $context = context_course::instance($section->course);
593 $summarytext = file_rewrite_pluginfile_urls($section->summary, 'pluginfile.php',
594 $context->id, 'course', 'section', $section->id);
595
596 $options = new stdClass();
597 $options->noclean = true;
598 $options->overflowdiv = true;
599 return format_text($summarytext, $section->summaryformat, $options);
600 }
1804b7c1 601}