From fdd4b9a50ad78de738eaf659ec769dcd55d643a4 Mon Sep 17 00:00:00 2001 From: Marina Glancy Date: Thu, 18 Oct 2012 09:38:36 +0800 Subject: [PATCH 1/3] MDL-36048 Allow course formats to add course headers and footers - Added functions in class format_base - Added global functions in course/lib.php - Added calling of course header/footer functions to the base theme - output renderer checks if theme calls the coures content header/footer functions, if not calls them explicitly and displays a development warning --- course/format/lib.php | 67 +++++++++++++++++++ lib/outputrenderers.php | 111 ++++++++++++++++++++++++++++++++ theme/base/config.php | 14 ++-- theme/base/layout/general.php | 20 +++++- theme/base/layout/report.php | 21 +++++- theme/base/style/core.css | 3 + theme/canvas/config.php | 14 ++-- theme/canvas/layout/general.php | 32 +++++++-- theme/canvas/layout/report.php | 31 +++++++-- theme/standard/style/core.css | 1 + 10 files changed, 283 insertions(+), 31 deletions(-) diff --git a/course/format/lib.php b/course/format/lib.php index 234f2e4ddc3..3e6af2021ac 100644 --- a/course/format/lib.php +++ b/course/format/lib.php @@ -785,6 +785,73 @@ abstract class format_base { */ public function page_set_cm(moodle_page $page) { } + + /** + * Course-specific information to be output on any course page (usually above navigation bar) + * + * Example of usage: + * define + * class format_FORMATNAME_XXX implements renderable {} + * + * create format renderer in course/format/FORMATNAME/renderer.php, define rendering function: + * class format_FORMATNAME_renderer extends plugin_renderer_base { + * protected function render_format_FORMATNAME_XXX(format_FORMATNAME_XXX $xxx) { + * return html_writer::tag('div', 'This is my header/footer'); + * } + * } + * + * Return instance of format_FORMATNAME_XXX in this function, the appropriate method from + * plugin renderer will be called + * + * @return null|renderable null for no output or object with data for plugin renderer + */ + public function course_header() { + return null; + } + + /** + * Course-specific information to be output on any course page (usually in the beginning of + * standard footer) + * + * See {@link format_base::course_header()} for usage + * + * @return null|renderable null for no output or object with data for plugin renderer + */ + public function course_footer() { + return null; + } + + /** + * Course-specific information to be output immediately above content on any course page + * + * See {@link format_base::course_header()} for usage + * + * @return null|renderable null for no output or object with data for plugin renderer + */ + public function course_content_header() { + return null; + } + + /** + * Course-specific information to be output immediately below content on any course page + * + * See {@link format_base::course_header()} for usage + * + * @return null|renderable null for no output or object with data for plugin renderer + */ + public function course_content_footer() { + return null; + } + + /** + * Returns instance of page renderer used by this plugin + * + * @param moodle_page $page + * @return renderer_base + */ + public function get_renderer(moodle_page $page) { + return $page->get_renderer('format_'. $this->get_format()); + } } /** diff --git a/lib/outputrenderers.php b/lib/outputrenderers.php index 6239615131c..c38de619a41 100644 --- a/lib/outputrenderers.php +++ b/lib/outputrenderers.php @@ -759,6 +759,23 @@ class core_renderer extends renderer_base { $header = $this->doctype() . $header; } + // If this theme version is below 2.4 release and this is a course view page + if ((!isset($this->page->theme->settings->version) || $this->page->theme->settings->version < 2012101500) && + $this->page->pagelayout === 'course' && $this->page->url->compare(new moodle_url('/course/view.php'), URL_MATCH_BASE)) { + // check if course content header/footer have not been output during render of theme layout + $coursecontentheader = $this->course_content_header(true); + $coursecontentfooter = $this->course_content_footer(true); + if (!empty($coursecontentheader)) { + // display debug message and add header and footer right above and below main content + // Please note that course header and footer (to be displayed above and below the whole page) + // are not displayed in this case at all. + // Besides the content header and footer are not displayed on any other course page + debugging('The current theme is not optimised for 2.4, the course-specific header and footer defined in course format will not be output', DEBUG_DEVELOPER); + $header .= $coursecontentheader; + $footer = $coursecontentfooter. $footer; + } + } + send_headers($this->contenttype, $this->page->cacheable); $this->opencontainers->push('header/footer', $footer); @@ -845,6 +862,100 @@ class core_renderer extends renderer_base { return $this->opencontainers->pop_all_but_last($shouldbenone); } + /** + * Returns course-specific information to be output immediately above content on any course page + * (for the current course) + * + * @param bool $onlyifnotcalledbefore output content only if it has not been output before + * @return string + */ + public function course_content_header($onlyifnotcalledbefore = false) { + global $CFG; + if ($this->page->course->id == SITEID) { + // return immediately and do not include /course/lib.php if not necessary + return ''; + } + static $functioncalled = false; + if ($functioncalled && $onlyifnotcalledbefore) { + // we have already output the content header + return ''; + } + require_once($CFG->dirroot.'/course/lib.php'); + $functioncalled = true; + $courseformat = course_get_format($this->page->course); + if (($obj = $courseformat->course_content_header()) !== null) { + return $courseformat->get_renderer($this->page)->render($obj); + } + return ''; + } + + /** + * Returns course-specific information to be output immediately below content on any course page + * (for the current course) + * + * @param bool $onlyifnotcalledbefore output content only if it has not been output before + * @return string + */ + public function course_content_footer($onlyifnotcalledbefore = false) { + global $CFG; + if ($this->page->course->id == SITEID) { + // return immediately and do not include /course/lib.php if not necessary + return ''; + } + static $functioncalled = false; + if ($functioncalled && $onlyifnotcalledbefore) { + // we have already output the content footer + return ''; + } + $functioncalled = true; + require_once($CFG->dirroot.'/course/lib.php'); + $courseformat = course_get_format($this->page->course); + if (($obj = $courseformat->course_content_footer()) !== null) { + return $courseformat->get_renderer($this->page)->render($obj); + } + return ''; + } + + /** + * Returns course-specific information to be output on any course page in the header area + * (for the current course) + * + * @return string + */ + public function course_header() { + global $CFG; + if ($this->page->course->id == SITEID) { + // return immediately and do not include /course/lib.php if not necessary + return ''; + } + require_once($CFG->dirroot.'/course/lib.php'); + $courseformat = course_get_format($this->page->course); + if (($obj = $courseformat->course_header()) !== null) { + return $courseformat->get_renderer($this->page)->render($obj); + } + return ''; + } + + /** + * Returns course-specific information to be output on any course page in the footer area + * (for the current course) + * + * @return string + */ + public function course_footer() { + global $CFG; + if ($this->page->course->id == SITEID) { + // return immediately and do not include /course/lib.php if not necessary + return ''; + } + require_once($CFG->dirroot.'/course/lib.php'); + $courseformat = course_get_format($this->page->course); + if (($obj = $courseformat->course_footer()) !== null) { + return $courseformat->get_renderer($this->page)->render($obj); + } + return ''; + } + /** * Returns lang menu or '', this method also checks forcing of languages in courses. * diff --git a/theme/base/config.php b/theme/base/config.php index cd85c660b47..d75cfc569b3 100644 --- a/theme/base/config.php +++ b/theme/base/config.php @@ -119,19 +119,19 @@ $THEME->layouts = array( 'popup' => array( 'file' => 'general.php', 'regions' => array(), - 'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true, 'nologininfo'=>true), + 'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true, 'nologininfo'=>true, 'nocourseheaderfooter'=>true), ), // No blocks and minimal footer - used for legacy frame layouts only! 'frametop' => array( 'file' => 'general.php', 'regions' => array(), - 'options' => array('nofooter'=>true), + 'options' => array('nofooter'=>true, 'nocoursefooter'=>true), ), // Embeded pages, like iframe/object embeded in moodleform - it needs as much space as possible 'embedded' => array( 'file' => 'embedded.php', 'regions' => array(), - 'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true), + 'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true, 'nocourseheaderfooter'=>true), ), // Used during upgrade and install, and for the 'This site is undergoing maintenance' message. // This must not have any blocks, and it is good idea if it does not have links to @@ -139,19 +139,19 @@ $THEME->layouts = array( 'maintenance' => array( 'file' => 'general.php', 'regions' => array(), - 'options' => array('noblocks'=>true, 'nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true), + 'options' => array('noblocks'=>true, 'nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true, 'nocourseheaderfooter'=>true), ), // Should display the content and basic headers only. 'print' => array( 'file' => 'general.php', 'regions' => array(), - 'options' => array('noblocks'=>true, 'nofooter'=>true, 'nonavbar'=>false, 'nocustommenu'=>true), + 'options' => array('noblocks'=>true, 'nofooter'=>true, 'nonavbar'=>false, 'nocustommenu'=>true, 'nocourseheaderfooter'=>true), ), // The pagelayout used when a redirection is occuring. 'redirect' => array( 'file' => 'embedded.php', 'regions' => array(), - 'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true), + 'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true, 'nocourseheaderfooter'=>true), ), // The pagelayout used for reports. 'report' => array( @@ -164,7 +164,7 @@ $THEME->layouts = array( 'file' => 'general.php', 'regions' => array('side-pre', 'side-post'), 'defaultregion' => 'side-pre', - 'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true, 'nologinlinks'=>true), + 'options' => array('nofooter'=>true, 'nonavbar'=>true, 'nocustommenu'=>true, 'nologinlinks'=>true, 'nocourseheaderfooter'=>true), ), ); diff --git a/theme/base/layout/general.php b/theme/base/layout/general.php index 9618515e600..1a0f9e41d6a 100644 --- a/theme/base/layout/general.php +++ b/theme/base/layout/general.php @@ -13,6 +13,16 @@ $showsidepost = ($hassidepost && !$PAGE->blocks->region_completely_docked('side- $custommenu = $OUTPUT->custom_menu(); $hascustommenu = (empty($PAGE->layout_options['nocustommenu']) && !empty($custommenu)); +$courseheader = $coursecontentheader = $coursecontentfooter = $coursefooter = ''; +if (empty($PAGE->layout_options['nocourseheaderfooter'])) { + $courseheader = $OUTPUT->course_header(); + $coursecontentheader = $OUTPUT->course_content_header(); + if (empty($PAGE->layout_options['nocoursefooter'])) { + $coursecontentfooter = $OUTPUT->course_content_footer(); + $coursefooter = $OUTPUT->course_footer(); + } +} + $bodyclasses = array(); if ($showsidepre && !$showsidepost) { if (!right_to_left()) { @@ -43,7 +53,7 @@ echo $OUTPUT->doctype() ?> standard_top_of_body_html() ?>
- + + +
+
@@ -76,7 +89,9 @@ echo $OUTPUT->doctype() ?>
+ main_content() ?> +
@@ -113,6 +128,9 @@ echo $OUTPUT->doctype() ?>
+ + +