diff --git a/course/format/lib.php b/course/format/lib.php index 7f6dfc99288..f0ccf9b1c0a 100644 --- a/course/format/lib.php +++ b/course/format/lib.php @@ -860,6 +860,23 @@ abstract class format_base { public function get_renderer(moodle_page $page) { return $page->get_renderer('format_'. $this->get_format()); } + + /** + * Returns true if the specified section is current + * + * By default we analyze $course->marker + * + * @param int|stdClass|section_info $section + * @return bool + */ + public function is_section_current($section) { + if (is_object($section)) { + $sectionnum = $section->section; + } else { + $sectionnum = $section; + } + return ($sectionnum && ($course = $this->get_course()) && $course->marker == $sectionnum); + } } /** diff --git a/course/format/renderer.php b/course/format/renderer.php index ea83ace3053..1856c624fb4 100644 --- a/course/format/renderer.php +++ b/course/format/renderer.php @@ -108,7 +108,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base { if ($section->section != 0) { // Only in the non-general sections. - if ($this->is_section_current($section, $course)) { + if (course_get_format($course)->is_section_current($section)) { $o = get_accesshide(get_string('currentsection', 'format_'.$course->format)); } } @@ -137,7 +137,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base { // Only in the non-general sections. if (!$section->visible) { $sectionstyle = ' hidden'; - } else if ($this->is_section_current($section, $course)) { + } else if (course_get_format($course)->is_section_current($section)) { $sectionstyle = ' current'; } } @@ -282,7 +282,7 @@ abstract class format_section_renderer_base extends plugin_renderer_base { if (!$section->visible) { $classattr .= ' hidden'; $linkclasses .= ' dimmed_text'; - } else if ($this->is_section_current($section, $course)) { + } else if (course_get_format($course)->is_section_current($section)) { $classattr .= ' current'; } @@ -760,14 +760,18 @@ abstract class format_section_renderer_base extends plugin_renderer_base { } /** - * Is the section passed in the current section? (Note this isn't strictly - * a renderering method, but neater here). + * Is the section passed in the current section? + * + * @deprecated since 2.4 + * @see format_base::is_section_current() * * @param stdClass $course The course entry from DB * @param stdClass $section The course_section entry from the DB * @return bool true if the section is current */ - protected function is_section_current($section, $course) { - return ($course->marker == $section->section); + protected final function is_section_current($section, $course) { + debugging('Function format_section_renderer_base::is_section_current() is deprecated. '. + 'Use course_get_format($course)->is_section_current($section) instead', DEBUG_DEVELOPER); + return course_get_format($course)->is_section_current($section); } } diff --git a/course/format/scorm/config.php b/course/format/scorm/config.php deleted file mode 100644 index 13bd6d636a9..00000000000 --- a/course/format/scorm/config.php +++ /dev/null @@ -1,11 +0,0 @@ -. /** - * This file contains general functions for the course format SCORM + * This file contains main class for the course format SCORM * - * @since 2.0 - * @package moodlecore + * @since 2.0 + * @package format_scorm * @copyright 2009 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ /** - * The string that is used to describe a section of the course - * e.g. Topic, Week... + * Main class for the Scorm course format * - * @return string + * @package format_scorm + * @copyright 2012 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -function callback_scorm_definition() { - return get_string('scorm'); +class format_scorm extends format_base { + + /** + * The URL to use for the specified course + * + * @param int|stdClass $section Section object from database or just field course_sections.section + * if null the course view page is returned + * @param array $options options for view URL. At the moment core uses: + * 'navigation' (bool) if true and section has no separate page, the function returns null + * 'sr' (int) used by multipage formats to specify to which section to return + * @return null|moodle_url + */ + public function get_view_url($section, $options = array()) { + if (!empty($options['navigation']) && $section !== null) { + return null; + } + return new moodle_url('/course/view.php', array('id' => $this->courseid)); + } + + /** + * Loads all of the course sections into the navigation + * + * @param global_navigation $navigation + * @param navigation_node $node The course node within the navigation + */ + public function extend_course_navigation($navigation, navigation_node $node) { + // Scorm course format does not extend course navigation + } + + /** + * Returns the list of blocks to be automatically added for the newly created course + * + * @return array of default blocks, must contain two keys BLOCK_POS_LEFT and BLOCK_POS_RIGHT + * each of values is an array of block names (for left and right side columns) + */ + public function get_default_blocks() { + return array( + BLOCK_POS_LEFT => array(), + BLOCK_POS_RIGHT => array('news_items', 'recent_activity', 'calendar_upcoming') + ); + } } - -/** - * Toogle display of course contents (sections, activities) - * - * @return bool - */ -function callback_scorm_display_content() { - return false; -} - - diff --git a/course/format/scorm/version.php b/course/format/scorm/version.php index 2583df5f39d..5890e40e5be 100644 --- a/course/format/scorm/version.php +++ b/course/format/scorm/version.php @@ -25,6 +25,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2012061700; // The current plugin version (Date: YYYYMMDDXX) -$plugin->requires = 2012061700; // Requires this Moodle version +$plugin->version = 2012110900; // The current plugin version (Date: YYYYMMDDXX) +$plugin->requires = 2012110900; // Requires this Moodle version $plugin->component = 'format_scorm'; // Full name of the plugin (used for diagnostics) diff --git a/course/format/social/config.php b/course/format/social/config.php deleted file mode 100644 index ed053355b2a..00000000000 --- a/course/format/social/config.php +++ /dev/null @@ -1,11 +0,0 @@ -. /** - * This file contains general functions for the course format Social + * This file contains main class for the course format Social * - * @since 2.0 - * @package moodlecore + * @since 2.0 + * @package format_social * @copyright 2009 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ /** - * Used to display the course structure for a course where format=social + * Main class for the Social course format * - * This is called automatically by {@link load_course()} if the current course - * format = weeks. - * - * @param array $path An array of keys to the course node in the navigation - * @param stdClass $modinfo The mod info object for the current course - * @return bool Returns true + * @package format_social + * @copyright 2012 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -function callback_social_load_content(&$navigation, $course, $coursenode) { - return $navigation->load_generic_course_sections($course, $coursenode, 'social'); +class format_social extends format_base { + + /** + * The URL to use for the specified course + * + * @param int|stdClass $section Section object from database or just field course_sections.section + * if null the course view page is returned + * @param array $options options for view URL. At the moment core uses: + * 'navigation' (bool) if true and section has no separate page, the function returns null + * 'sr' (int) used by multipage formats to specify to which section to return + * @return null|moodle_url + */ + public function get_view_url($section, $options = array()) { + if (!empty($options['navigation']) && $section !== null) { + return null; + } + return new moodle_url('/course/view.php', array('id' => $this->courseid)); + } + + /** + * Loads all of the course sections into the navigation + * + * @param global_navigation $navigation + * @param navigation_node $node The course node within the navigation + */ + public function extend_course_navigation($navigation, navigation_node $node) { + // Social course format does not extend navigation, it uses social_activities block instead + } + + /** + * Returns the list of blocks to be automatically added for the newly created course + * + * @return array of default blocks, must contain two keys BLOCK_POS_LEFT and BLOCK_POS_RIGHT + * each of values is an array of block names (for left and right side columns) + */ + public function get_default_blocks() { + return array( + BLOCK_POS_LEFT => array(), + BLOCK_POS_RIGHT => array('search_forums', 'calendar_upcoming', 'social_activities', + 'recent_activity', 'course_list') + ); + } } - -/** - * Used to display the course structure for a course where format=social - * - * This is called automatically by {@link load_course()} if the current course - * format = weeks and the navigation was requested via AJAX - * - * @param array $path An array of keys to the course node in the navigation - * @param stdClass $modinfo The mod info object for the current course - * @return bool Returns true - */ -function limited_load_section_social(&$navigation, $keys, $course, $section) { - $navigation->limited_load_section_generic($keys, $course, $section, get_string('social'), 'social'); -} - -/** - * Indicates this format uses sections. - * - * @return bool Returns true - */ -function callback_social_uses_sections() { - return false; -} - -/** - * The string that is used to describe a section of the course - * e.g. Topic, Week... - * - * @return string - */ -function callback_social_definition() { - return get_string('topic'); -} - -/** - * Toogle display of course contents (sections, activities) - * - * @return bool - */ -function callback_social_display_content() { - return false; -} - - diff --git a/course/format/social/version.php b/course/format/social/version.php index 7fe4f6a418e..2002e733cce 100644 --- a/course/format/social/version.php +++ b/course/format/social/version.php @@ -25,6 +25,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2012061700; // The current plugin version (Date: YYYYMMDDXX) -$plugin->requires = 2012061700; // Requires this Moodle version +$plugin->version = 2012110900; // The current plugin version (Date: YYYYMMDDXX) +$plugin->requires = 2012110900; // Requires this Moodle version $plugin->component = 'format_social'; // Full name of the plugin (used for diagnostics) diff --git a/course/format/topics/config.php b/course/format/topics/config.php deleted file mode 100644 index 1a429b4e459..00000000000 --- a/course/format/topics/config.php +++ /dev/null @@ -1,10 +0,0 @@ -. /** - * This file contains general functions for the course format Topic + * This file contains main class for the course format Topic * - * @since 2.0 - * @package moodlecore + * @since 2.0 + * @package format_topics * @copyright 2009 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ - /** - * Indicates this format uses sections. + * Main class for the Topics course format * - * @return bool Returns true + * @package format_topics + * @copyright 2012 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -function callback_topics_uses_sections() { - return true; -} +class format_topics extends format_base { -/** - * Used to display the course structure for a course where format=topic - * - * This is called automatically by {@link load_course()} if the current course - * format = weeks. - * - * @param array $path An array of keys to the course node in the navigation - * @param stdClass $modinfo The mod info object for the current course - * @return bool Returns true - */ -function callback_topics_load_content(&$navigation, $course, $coursenode) { - return $navigation->load_generic_course_sections($course, $coursenode, 'topics'); -} - -/** - * The string that is used to describe a section of the course - * e.g. Topic, Week... - * - * @return string - */ -function callback_topics_definition() { - return get_string('topic'); -} - -function callback_topics_get_section_name($course, $section) { - // We can't add a node without any text - if ((string)$section->name !== '') { - return format_string($section->name, true, array('context' => context_course::instance($course->id))); - } else if ($section->section == 0) { - return get_string('section0name', 'format_topics'); - } else { - return get_string('topic').' '.$section->section; + /** + * Returns true if this course format uses sections + * + * @return bool + */ + public function uses_sections() { + return true; } -} -/** - * Declares support for course AJAX features - * - * @see course_format_ajax_support() - * @return stdClass - */ -function callback_topics_ajax_support() { - $ajaxsupport = new stdClass(); - $ajaxsupport->capable = true; - $ajaxsupport->testedbrowsers = array('MSIE' => 6.0, 'Gecko' => 20061111, 'Safari' => 531, 'Chrome' => 6.0); - return $ajaxsupport; -} - -/** - * Callback function to do some action after section move - * - * @param stdClass $course The course entry from DB - * @return array This will be passed in ajax respose. - */ -function callback_topics_ajax_section_move($course) { - global $COURSE, $PAGE; - - $titles = array(); - rebuild_course_cache($course->id); - $modinfo = get_fast_modinfo($COURSE); - $renderer = $PAGE->get_renderer('format_topics'); - if ($renderer && ($sections = $modinfo->get_section_info_all())) { - foreach ($sections as $number => $section) { - $titles[$number] = $renderer->section_title($section, $course); + /** + * Returns the display name of the given section that the course prefers. + * + * Use section name is specified by user. Otherwise use default ("Topic #") + * + * @param int|stdClass $section Section object from database or just field section.section + * @return string Display name that the course format prefers, e.g. "Topic 2" + */ + public function get_section_name($section) { + $section = $this->get_section($section); + if ((string)$section->name !== '') { + return format_string($section->name, true, + array('context' => context_course::instance($this->courseid))); + } else if ($section->section == 0) { + return get_string('section0name', 'format_topics'); + } else { + return get_string('topic').' '.$section->section; } } - return array('sectiontitles' => $titles, 'action' => 'move'); + + /** + * The URL to use for the specified course (with section) + * + * @param int|stdClass $section Section object from database or just field course_sections.section + * if omitted the course view page is returned + * @param array $options options for view URL. At the moment core uses: + * 'navigation' (bool) if true and section has no separate page, the function returns null + * 'sr' (int) used by multipage formats to specify to which section to return + * @return null|moodle_url + */ + public function get_view_url($section, $options = array()) { + $course = $this->get_course(); + $url = new moodle_url('/course/view.php', array('id' => $course->id)); + + $sr = null; + if (array_key_exists('sr', $options)) { + $sr = $options['sr']; + } + if (is_object($section)) { + $sectionno = $section->section; + } else { + $sectionno = $section; + } + if ($sectionno !== null) { + if ($sr !== null) { + if ($sr) { + $usercoursedisplay = COURSE_DISPLAY_MULTIPAGE; + $sectionno = $sr; + } else { + $usercoursedisplay = COURSE_DISPLAY_SINGLEPAGE; + } + } else { + $usercoursedisplay = $course->coursedisplay; + } + if ($sectionno != 0 && $usercoursedisplay == COURSE_DISPLAY_MULTIPAGE) { + $url->param('section', $sectionno); + } else { + if (!empty($options['navigation'])) { + return null; + } + $url->set_anchor('section-'.$sectionno); + } + } + return $url; + } + + /** + * Returns the information about the ajax support in the given source format + * + * The returned object's property (boolean)capable indicates that + * the course format supports Moodle course ajax features. + * The property (array)testedbrowsers can be used as a parameter for {@link ajaxenabled()}. + * + * @return stdClass + */ + public function supports_ajax() { + $ajaxsupport = new stdClass(); + $ajaxsupport->capable = true; + $ajaxsupport->testedbrowsers = array('MSIE' => 6.0, 'Gecko' => 20061111, 'Safari' => 531, 'Chrome' => 6.0); + return $ajaxsupport; + } + + /** + * Loads all of the course sections into the navigation + * + * @param global_navigation $navigation + * @param navigation_node $node The course node within the navigation + */ + public function extend_course_navigation($navigation, navigation_node $node) { + global $PAGE; + // if section is specified in course/view.php, make sure it is expanded in navigation + if ($navigation->includesectionnum === false) { + $selectedsection = optional_param('section', null, PARAM_INT); + if ($selectedsection !== null && (!defined('AJAX_SCRIPT') || AJAX_SCRIPT == '0') && + $PAGE->url->compare(new moodle_url('/course/view.php'), URL_MATCH_BASE)) { + $navigation->includesectionnum = $selectedsection; + } + } + + // check if there are callbacks to extend course navigation + parent::extend_course_navigation($navigation, $node); + } + + /** + * Custom action after section has been moved in AJAX mode + * + * Used in course/rest.php + * + * @return array This will be passed in ajax respose + */ + function ajax_section_move() { + global $PAGE; + $titles = array(); + $course = $this->get_course(); + $modinfo = get_fast_modinfo($course); + $renderer = $this->get_renderer($PAGE); + if ($renderer && ($sections = $modinfo->get_section_info_all())) { + foreach ($sections as $number => $section) { + $titles[$number] = $renderer->section_title($section, $course); + } + } + return array('sectiontitles' => $titles, 'action' => 'move'); + } + + /** + * Returns the list of blocks to be automatically added for the newly created course + * + * @return array of default blocks, must contain two keys BLOCK_POS_LEFT and BLOCK_POS_RIGHT + * each of values is an array of block names (for left and right side columns) + */ + public function get_default_blocks() { + return array( + BLOCK_POS_LEFT => array(), + BLOCK_POS_RIGHT => array('search_forums', 'news_items', 'calendar_upcoming', 'recent_activity') + ); + } + + /** + * Definitions of the additional options that this course format uses for course + * + * Topics format uses the following options: + * - coursedisplay + * - numsections + * - hiddensections + * + * @param bool $foreditform + * @return array of options + */ + public function course_format_options($foreditform = false) { + static $courseformatoptions = false; + if ($courseformatoptions === false) { + $courseconfig = get_config('moodlecourse'); + $courseformatoptions = array( + 'numsections' => array( + 'default' => $courseconfig->numsections, + 'type' => PARAM_INT, + ), + 'hiddensections' => array( + 'default' => $courseconfig->hiddensections, + 'type' => PARAM_INT, + ), + 'coursedisplay' => array( + 'default' => $courseconfig->coursedisplay, + 'type' => PARAM_INT, + ), + ); + } + if ($foreditform && !isset($courseformatoptions['coursedisplay']['label'])) { + $courseconfig = get_config('moodlecourse'); + $sectionmenu = array(); + for ($i = 0; $i <= $courseconfig->maxsections; $i++) { + $sectionmenu[$i] = "$i"; + } + $courseformatoptionsedit = array( + 'numsections' => array( + 'label' => new lang_string('numberweeks'), + 'element_type' => 'select', + 'element_attributes' => array($sectionmenu), + ), + 'hiddensections' => array( + 'label' => new lang_string('hiddensections'), + 'help' => 'hiddensections', + 'help_component' => 'moodle', + 'element_type' => 'select', + 'element_attributes' => array( + array( + 0 => new lang_string('hiddensectionscollapsed'), + 1 => new lang_string('hiddensectionsinvisible') + ) + ), + ), + 'coursedisplay' => array( + 'label' => new lang_string('coursedisplay'), + 'element_type' => 'select', + 'element_attributes' => array( + array( + COURSE_DISPLAY_SINGLEPAGE => new lang_string('coursedisplay_single'), + COURSE_DISPLAY_MULTIPAGE => new lang_string('coursedisplay_multi') + ) + ), + 'help' => 'coursedisplay', + 'help_component' => 'moodle', + ) + ); + $courseformatoptions = array_merge_recursive($courseformatoptions, $courseformatoptionsedit); + } + return $courseformatoptions; + } + + /** + * Updates format options for a course + * + * In case if course format was changed to 'topics', we try to copy options + * 'coursedisplay', 'numsections' and 'hiddensections' from the previous format. + * If previous course format did not have 'numsections' option, we populate it with the + * current number of sections + * + * @param stdClass|array $data return value from {@link moodleform::get_data()} or array with data + * @param stdClass $oldcourse if this function is called from {@link update_course()} + * this object contains information about the course before update + * @return bool whether there were any changes to the options values + */ + public function update_course_format_options($data, $oldcourse = null) { + if ($oldcourse !== null) { + $data = (array)$data; + $oldcourse = (array)$oldcourse; + $options = $this->course_format_options(); + foreach ($options as $key => $unused) { + if (!array_key_exists($key, $data)) { + if (array_key_exists($key, $oldcourse)) { + $data[$key] = $oldcourse[$key]; + } else if ($key === 'numsections') { + // If previous format does not have the field 'numsections' + // and $data['numsections'] is not set, + // we fill it with the maximum section number from the DB + $maxsection = $DB->get_field_sql('SELECT max(section) from {course_sections} + WHERE course = ?', array($this->courseid)); + if ($maxsection) { + // If there are no sections, or just default 0-section, 'numsections' will be set to default + $data['numsections'] = $maxsection; + } + } + } + } + } + return $this->update_format_options($data); + } } diff --git a/course/format/topics/version.php b/course/format/topics/version.php index b2bba53e288..738d39033ef 100644 --- a/course/format/topics/version.php +++ b/course/format/topics/version.php @@ -25,6 +25,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2012061700; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2012061700; // Requires this Moodle version. +$plugin->version = 2012110900; // The current plugin version (Date: YYYYMMDDXX). +$plugin->requires = 2012110900; // Requires this Moodle version. $plugin->component = 'format_topics'; // Full name of the plugin (used for diagnostics). diff --git a/course/format/upgrade.txt b/course/format/upgrade.txt index f14a8912052..4c5d1313cc3 100644 --- a/course/format/upgrade.txt +++ b/course/format/upgrade.txt @@ -13,6 +13,8 @@ format. * functions get_generic_section_name(), get_all_sections(), add_mod_to_section(), get_all_mods() are deprecated. See their phpdocs in lib/deprecatedlib.php on how to replace them * Course formats may now have their settings.php file as the most of other plugin types +* Function format_section_renderer_base::is_section_current() is deprecated, overwrite/use + function is_section_current in format class === 2.3 === diff --git a/course/format/weeks/config.php b/course/format/weeks/config.php deleted file mode 100644 index 1a429b4e459..00000000000 --- a/course/format/weeks/config.php +++ /dev/null @@ -1,10 +0,0 @@ -. /** - * This file contains general functions for the course format Week + * This file contains main class for the course format Weeks * - * @since 2.0 - * @package moodlecore + * @since 2.0 + * @package format_weeks * @copyright 2009 Sam Hemelryk * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ - /** - * Indicates this format uses sections. + * Main class for the Weeks course format * - * @return bool Returns true + * @package format_weeks + * @copyright 2012 Marina Glancy + * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later */ -function callback_weeks_uses_sections() { - return true; -} +class format_weeks extends format_base { -/** - * Used to display the course structure for a course where format=weeks - * - * This is called automatically by {@link load_course()} if the current course - * format = weeks. - * - * @param navigation_node $navigation The course node - * @param array $path An array of keys to the course node - * @param stdClass $course The course we are loading the section for - */ -function callback_weeks_load_content(&$navigation, $course, $coursenode) { - return $navigation->load_generic_course_sections($course, $coursenode, 'weeks'); -} - -/** - * The string that is used to describe a section of the course - * e.g. Topic, Week... - * - * @return string - */ -function callback_weeks_definition() { - return get_string('week'); -} - -/** - * Gets the name for the provided section. - * - * @param stdClass $course - * @param stdClass $section - * @return string - */ -function callback_weeks_get_section_name($course, $section) { - // We can't add a node without text - if ((string)$section->name !== '') { - // Return the name the user set. - return format_string($section->name, true, array('context' => context_course::instance($course->id))); - } else if ($section->section == 0) { - // Return the general section. - return get_string('section0name', 'format_weeks'); - } else { - $dates = format_weeks_get_section_dates($section, $course); - - // We subtract 24 hours for display purposes. - $dates->end = ($dates->end - 86400); - - $dateformat = ' '.get_string('strftimedateshort'); - $weekday = userdate($dates->start, $dateformat); - $endweekday = userdate($dates->end, $dateformat); - return $weekday.' - '.$endweekday; + /** + * Returns true if this course format uses sections + * + * @return bool + */ + public function uses_sections() { + return true; } -} -/** - * Declares support for course AJAX features - * - * @see course_format_ajax_support() - * @return stdClass - */ -function callback_weeks_ajax_support() { - $ajaxsupport = new stdClass(); - $ajaxsupport->capable = true; - $ajaxsupport->testedbrowsers = array('MSIE' => 6.0, 'Gecko' => 20061111, 'Safari' => 531, 'Chrome' => 6.0); - return $ajaxsupport; -} + /** + * Returns the display name of the given section that the course prefers. + * + * @param int|stdClass $section Section object from database or just field section.section + * @return string Display name that the course format prefers, e.g. "Topic 2" + */ + public function get_section_name($section) { + $section = $this->get_section($section); + if ((string)$section->name !== '') { + // Return the name the user set. + return format_string($section->name, true, array('context' => context_course::instance($this->courseid))); + } else if ($section->section == 0) { + // Return the general section. + return get_string('section0name', 'format_weeks'); + } else { + $dates = $this->get_section_dates($section); -/** - * Return the start and end date of the passed section - * - * @param stdClass $section The course_section entry from the DB - * @param stdClass $course The course entry from DB - * @return stdClass property start for startdate, property end for enddate - */ -function format_weeks_get_section_dates($section, $course) { - $oneweekseconds = 604800; - // Hack alert. We add 2 hours to avoid possible DST problems. (e.g. we go into daylight - // savings and the date changes. - $startdate = $course->startdate + 7200; + // We subtract 24 hours for display purposes. + $dates->end = ($dates->end - 86400); - $dates = new stdClass(); - $dates->start = $startdate + ($oneweekseconds * ($section->section - 1)); - $dates->end = $dates->start + $oneweekseconds; - - return $dates; -} - -/** - * Callback function to do some action after section move - * - * @param stdClass $course The course entry from DB - * @return array This will be passed in ajax respose. - */ -function callback_weeks_ajax_section_move($course) { - global $COURSE, $PAGE; - - $titles = array(); - rebuild_course_cache($course->id); - $modinfo = get_fast_modinfo($COURSE); - $renderer = $PAGE->get_renderer('format_weeks'); - if ($renderer && ($sections = $modinfo->get_section_info_all())) { - foreach ($sections as $number => $section) { - $titles[$number] = $renderer->section_title($section, $course); + $dateformat = ' '.get_string('strftimedateshort'); + $weekday = userdate($dates->start, $dateformat); + $endweekday = userdate($dates->end, $dateformat); + return $weekday.' - '.$endweekday; } } - return array('sectiontitles' => $titles, 'action' => 'move'); + + /** + * The URL to use for the specified course (with section) + * + * @param int|stdClass $section Section object from database or just field course_sections.section + * if omitted the course view page is returned + * @param array $options options for view URL. At the moment core uses: + * 'navigation' (bool) if true and section has no separate page, the function returns null + * 'sr' (int) used by multipage formats to specify to which section to return + * @return null|moodle_url + */ + public function get_view_url($section, $options = array()) { + $course = $this->get_course(); + $url = new moodle_url('/course/view.php', array('id' => $course->id)); + + $sr = null; + if (array_key_exists('sr', $options)) { + $sr = $options['sr']; + } + if (is_object($section)) { + $sectionno = $section->section; + } else { + $sectionno = $section; + } + if ($sectionno !== null) { + if ($sr !== null) { + if ($sr) { + $usercoursedisplay = COURSE_DISPLAY_MULTIPAGE; + $sectionno = $sr; + } else { + $usercoursedisplay = COURSE_DISPLAY_SINGLEPAGE; + } + } else { + $usercoursedisplay = $course->coursedisplay; + } + if ($sectionno != 0 && $usercoursedisplay == COURSE_DISPLAY_MULTIPAGE) { + $url->param('section', $sectionno); + } else { + if (!empty($options['navigation'])) { + return null; + } + $url->set_anchor('section-'.$sectionno); + } + } + return $url; + } + + /** + * Returns the information about the ajax support in the given source format + * + * The returned object's property (boolean)capable indicates that + * the course format supports Moodle course ajax features. + * The property (array)testedbrowsers can be used as a parameter for {@link ajaxenabled()}. + * + * @return stdClass + */ + public function supports_ajax() { + $ajaxsupport = new stdClass(); + $ajaxsupport->capable = true; + $ajaxsupport->testedbrowsers = array('MSIE' => 6.0, 'Gecko' => 20061111, 'Safari' => 531, 'Chrome' => 6.0); + return $ajaxsupport; + } + + /** + * Loads all of the course sections into the navigation + * + * @param global_navigation $navigation + * @param navigation_node $node The course node within the navigation + */ + public function extend_course_navigation($navigation, navigation_node $node) { + global $PAGE; + // if section is specified in course/view.php, make sure it is expanded in navigation + if ($navigation->includesectionnum === false) { + $selectedsection = optional_param('section', null, PARAM_INT); + if ($selectedsection !== null && (!defined('AJAX_SCRIPT') || AJAX_SCRIPT == '0') && + $PAGE->url->compare(new moodle_url('/course/view.php'), URL_MATCH_BASE)) { + $navigation->includesectionnum = $selectedsection; + } + } + parent::extend_course_navigation($navigation, $node); + } + + /** + * Custom action after section has been moved in AJAX mode + * + * Used in course/rest.php + * + * @return array This will be passed in ajax respose + */ + function ajax_section_move() { + global $PAGE; + $titles = array(); + $course = $this->get_course(); + $modinfo = get_fast_modinfo($course); + $renderer = $this->get_renderer($PAGE); + if ($renderer && ($sections = $modinfo->get_section_info_all())) { + foreach ($sections as $number => $section) { + $titles[$number] = $renderer->section_title($section, $course); + } + } + return array('sectiontitles' => $titles, 'action' => 'move'); + } + + /** + * Returns the list of blocks to be automatically added for the newly created course + * + * @return array of default blocks, must contain two keys BLOCK_POS_LEFT and BLOCK_POS_RIGHT + * each of values is an array of block names (for left and right side columns) + */ + public function get_default_blocks() { + return array( + BLOCK_POS_LEFT => array(), + BLOCK_POS_RIGHT => array('search_forums', 'news_items', 'calendar_upcoming', 'recent_activity') + ); + } + + /** + * Definitions of the additional options that this course format uses for course + * + * Weeks format uses the following options: + * - coursedisplay + * - numsections + * - hiddensections + * + * @param bool $foreditform + * @return array of options + */ + public function course_format_options($foreditform = false) { + static $courseformatoptions = false; + if ($courseformatoptions === false) { + $courseconfig = get_config('moodlecourse'); + $courseformatoptions = array( + 'numsections' => array( + 'default' => $courseconfig->numsections, + 'type' => PARAM_INT, + ), + 'hiddensections' => array( + 'default' => $courseconfig->hiddensections, + 'type' => PARAM_INT, + ), + 'coursedisplay' => array( + 'default' => $courseconfig->coursedisplay, + 'type' => PARAM_INT, + ), + ); + } + if ($foreditform && !isset($courseformatoptions['coursedisplay']['label'])) { + $courseconfig = get_config('moodlecourse'); + $sectionmenu = array(); + for ($i = 0; $i <= $courseconfig->maxsections; $i++) { + $sectionmenu[$i] = "$i"; + } + $courseformatoptionsedit = array( + 'numsections' => array( + 'label' => new lang_string('numberweeks'), + 'element_type' => 'select', + 'element_attributes' => array($sectionmenu), + ), + 'hiddensections' => array( + 'label' => new lang_string('hiddensections'), + 'help' => 'hiddensections', + 'help_component' => 'moodle', + 'element_type' => 'select', + 'element_attributes' => array( + array( + 0 => new lang_string('hiddensectionscollapsed'), + 1 => new lang_string('hiddensectionsinvisible') + ) + ), + ), + 'coursedisplay' => array( + 'label' => new lang_string('coursedisplay'), + 'element_type' => 'select', + 'element_attributes' => array( + array( + COURSE_DISPLAY_SINGLEPAGE => new lang_string('coursedisplay_single'), + COURSE_DISPLAY_MULTIPAGE => new lang_string('coursedisplay_multi') + ) + ), + 'help' => 'coursedisplay', + 'help_component' => 'moodle', + ) + ); + $courseformatoptions = array_merge_recursive($courseformatoptions, $courseformatoptionsedit); + } + return $courseformatoptions; + } + + /** + * Updates format options for a course + * + * In case if course format was changed to 'weeks', we try to copy options + * 'coursedisplay', 'numsections' and 'hiddensections' from the previous format. + * If previous course format did not have 'numsections' option, we populate it with the + * current number of sections + * + * @param stdClass|array $data return value from {@link moodleform::get_data()} or array with data + * @param stdClass $oldcourse if this function is called from {@link update_course()} + * this object contains information about the course before update + * @return bool whether there were any changes to the options values + */ + public function update_course_format_options($data, $oldcourse = null) { + if ($oldcourse !== null) { + $data = (array)$data; + $oldcourse = (array)$oldcourse; + $options = $this->course_format_options(); + foreach ($options as $key => $unused) { + if (!array_key_exists($key, $data)) { + if (array_key_exists($key, $oldcourse)) { + $data[$key] = $oldcourse[$key]; + } else if ($key === 'numsections') { + // If previous format does not have the field 'numsections' + // and $data['numsections'] is not set, + // we fill it with the maximum section number from the DB + $maxsection = $DB->get_field_sql('SELECT max(section) from {course_sections} + WHERE course = ?', array($this->courseid)); + if ($maxsection) { + // If there are no sections, or just default 0-section, 'numsections' will be set to default + $data['numsections'] = $maxsection; + } + } + } + } + } + return $this->update_format_options($data); + } + + /** + * Return the start and end date of the passed section + * + * @param int|stdClass|section_info $section section to get the dates for + * @return stdClass property start for startdate, property end for enddate + */ + public function get_section_dates($section) { + $course = $this->get_course(); + if (is_object($section)) { + $sectionnum = $section->section; + } else { + $sectionnum = $section; + } + $oneweekseconds = 604800; + // Hack alert. We add 2 hours to avoid possible DST problems. (e.g. we go into daylight + // savings and the date changes. + $startdate = $course->startdate + 7200; + + $dates = new stdClass(); + $dates->start = $startdate + ($oneweekseconds * ($sectionnum - 1)); + $dates->end = $dates->start + $oneweekseconds; + + return $dates; + } + + /** + * Returns true if the specified week is current + * + * @param int|stdClass|section_info $section + * @return bool + */ + public function is_section_current($section) { + if (is_object($section)) { + $sectionnum = $section->section; + } else { + $sectionnum = $section; + } + if ($sectionnum < 1) { + return false; + } + $timenow = time(); + $dates = $this->get_section_dates($section); + return (($timenow >= $dates->start) && ($timenow < $dates->end)); + } } diff --git a/course/format/weeks/renderer.php b/course/format/weeks/renderer.php index e87936ccbf5..33590fdc87e 100644 --- a/course/format/weeks/renderer.php +++ b/course/format/weeks/renderer.php @@ -59,22 +59,4 @@ class format_weeks_renderer extends format_section_renderer_base { protected function page_title() { return get_string('weeklyoutline'); } - - /** - * Is the section passed in the current section? - * - * @param stdClass $section The course_section entry from the DB - * @param stdClass $course The course entry from DB - * @return bool true if the section is current - */ - protected function is_section_current($section, $course) { - if ($section->section < 1) { - return false; - } - - $timenow = time(); - $dates = format_weeks_get_section_dates($section, $course); - - return (($timenow >= $dates->start) && ($timenow < $dates->end)); - } } diff --git a/course/format/weeks/version.php b/course/format/weeks/version.php index 6a2d2c89c74..b89185e315c 100644 --- a/course/format/weeks/version.php +++ b/course/format/weeks/version.php @@ -25,6 +25,6 @@ defined('MOODLE_INTERNAL') || die(); -$plugin->version = 2012061700; // The current plugin version (Date: YYYYMMDDXX). -$plugin->requires = 2012061700; // Requires this Moodle version. +$plugin->version = 2012110900; // The current plugin version (Date: YYYYMMDDXX). +$plugin->requires = 2012110900; // Requires this Moodle version. $plugin->component = 'format_weeks'; // Full name of the plugin (used for diagnostics). diff --git a/lib/deprecatedlib.php b/lib/deprecatedlib.php index 1a2b205c15e..900b6e72b93 100644 --- a/lib/deprecatedlib.php +++ b/lib/deprecatedlib.php @@ -3044,3 +3044,24 @@ function get_course_section($section, $courseid) { rebuild_course_cache($courseid, true); return $DB->get_record("course_sections", array("id"=>$id)); } + +/** + * Return the start and end date of the week in Weekly course format + * + * It is not recommended to use this function outside of format_weeks plugin + * + * @deprecated since 2.4 + * @see format_weeks::get_section_dates() + * + * @param stdClass $section The course_section entry from the DB + * @param stdClass $course The course entry from DB + * @return stdClass property start for startdate, property end for enddate + */ +function format_weeks_get_section_dates($section, $course) { + debugging('Function format_weeks_get_section_dates() is deprecated. It is not recommended to'. + ' use it outside of format_weeks plugin', DEBUG_DEVELOPER); + if (isset($course->format) && $course->format === 'weeks') { + return course_get_format($course)->get_section_dates($section); + } + return null; +}